- if (utf8_to_locale == (iconv_t) -1 && (open_conversion_contexts() == -1))
- return NULL;
- assert(utf8_to_locale != (iconv_t) -1);
- /* make sure we start from an empty state */
- iconv(utf8_to_locale, NULL, NULL, NULL, NULL);
- if (conv_fails != NULL) *conv_fails = 0;
- /* set up output buffer (empty it) */
- outptr = outbuffer;
- outsize = outbufsize;
- memset(outbuffer, 0, outbufsize);
- nconv = iconv(utf8_to_locale, &inptr, &insize, &outptr, &outsize);
- while (nconv == (size_t)-1) {
- if (errno == E2BIG) {
- /* grow the output buffer */
- size_t outlen;
- outlen = outptr - outbuffer;
- outbufsize *= 2;
- outbuffer = realloc(outbuffer, outbufsize);
- outptr = outbuffer + outlen;
- outsize = outbufsize - outlen;
- memset(outptr, 0, outsize);
- }
- else if (errno == EILSEQ) {
- /* skip over character */
- const char* unkn_ptr = the_unknown;
- if (conv_fails != NULL) (*conv_fails)++;
- if ((*inptr & 0x80) == 0) {
- /* an ASCII character, just skip one (this case is very improbable) */
- inptr++; insize--;
- }
- else {
- /* a general UTF-8 character, skip all 0x10xxxxxx bytes */
- inptr++; insize--;
- while ((*inptr & 0xC0) == 0x80) {
- inptr++; insize--;
- }
- }
- /* append the "unknown" string to the output */
- while (*unkn_ptr) { *outptr++ = *unkn_ptr++; outsize--; }
- }
- else {
- /* EINVAL should not happen, since we convert entire strings */
- /* EBADF is an error which should be captured by the assert above */
- return NULL;
- }
- nconv = iconv(utf8_to_locale, &inptr, &insize, &outptr, &outsize);
- }
- return outbuffer;