This function converts the chars in the "in" xbuf into characters in the * "out" xbuf. The ".len" chars of the "in" xbuf is used starting from its * ".pos". The ".size" of the "out" xbuf restricts how many characters can * be stored, starting at its ".pos+.len" position. Note that the last byte * of the "out" xbuf is not used, which reserves space for a trailing '\0' * (though it is up to
| 177 | * If ICB_INIT is set, the iconv() conversion state is initialized prior to |
| 178 | * processing the characters. */ |
| 179 | int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags) |
| 180 | { |
| 181 | ICONV_CONST char *ibuf; |
| 182 | size_t icnt, ocnt, opos; |
| 183 | char *obuf; |
| 184 | |
| 185 | if (!out->size && flags & ICB_EXPAND_OUT) { |
| 186 | size_t siz = ROUND_UP_1024(in->len * 2); |
| 187 | alloc_xbuf(out, siz); |
| 188 | } else if (out->len+1 >= out->size) { |
| 189 | /* There is no room to even start storing data. */ |
| 190 | if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) { |
| 191 | errno = E2BIG; |
| 192 | return -1; |
| 193 | } |
| 194 | realloc_xbuf(out, out->size + ROUND_UP_1024(in->len * 2)); |
| 195 | } |
| 196 | |
| 197 | if (flags & ICB_INIT) |
| 198 | iconv(ic, NULL, 0, NULL, 0); |
| 199 | |
| 200 | ibuf = in->buf + in->pos; |
| 201 | icnt = in->len; |
| 202 | |
| 203 | opos = out->pos + out->len; |
| 204 | if (flags & ICB_CIRCULAR_OUT) { |
| 205 | if (opos >= out->size) { |
| 206 | opos -= out->size; |
| 207 | /* We know that out->pos is not 0 due to the "no room" check |
| 208 | * above, so this can't go "negative". */ |
| 209 | ocnt = out->pos - opos - 1; |
| 210 | } else { |
| 211 | /* Allow the use of all bytes to the physical end of the buffer |
| 212 | * unless pos is 0, in which case we reserve our trailing '\0'. */ |
| 213 | ocnt = out->size - opos - (out->pos ? 0 : 1); |
| 214 | } |
| 215 | } else |
| 216 | ocnt = out->size - opos - 1; |
| 217 | obuf = out->buf + opos; |
| 218 | |
| 219 | while (icnt) { |
| 220 | while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) { |
| 221 | if (errno == EINTR) |
| 222 | continue; |
| 223 | if (errno == EINVAL) { |
| 224 | if (!(flags & ICB_INCLUDE_INCOMPLETE)) |
| 225 | goto finish; |
| 226 | if (!ocnt) |
| 227 | goto e2big; |
| 228 | } else if (errno == EILSEQ) { |
| 229 | if (!(flags & ICB_INCLUDE_BAD)) |
| 230 | goto finish; |
| 231 | if (!ocnt) |
| 232 | goto e2big; |
| 233 | } else if (errno == E2BIG) { |
| 234 | size_t siz; |
| 235 | e2big: |
| 236 | opos = obuf - out->buf; |
no test coverage detected