static void convertWithIConv(struct OMRPortLibrary *portLibrary, char *error, char *errBuf, uintptr_t bufLen) { iconv_t converter; size_t inbytesleft, outbytesleft; char *inbuf, *outbuf; converter = iconv_get(portLibrary, J9SL_ICONV_DESCRIPTOR, "UTF-8", nl_langinfo(CODESET)); if (J9VM_INVALID_ICONV_DESCRIPTOR == converter) { /* no converter available for this code set. Just dump the platform chars */ strncpy(errBuf, error, bufLen); errBuf[bufLen - 1] = '\0'; return; } inbuf = (char *)error; /* for some reason this argument isn't const */ outbuf = errBuf; inbytesleft = strlen(error); outbytesleft = bufLen - 1; while ((outbytesleft > 0) && (inbytesleft > 0)) { if ((size_t)-1 == iconv(converter, &inbuf, &inbytesleft, &outbuf, &outbytesleft)) { if (E2BIG == errno) { break; } /* if we couldn't translate this character, copy one byte verbatim */ *outbuf = *inbuf; outbuf++; inbuf++; inbytesleft--; outbytesleft--; } } *outbuf = '\0'; iconv_free(portLibrary, J9SL_ICONV_DESCRIPTOR, converter); }
static intptr_t file_write_using_iconv(struct OMRPortLibrary *portLibrary, intptr_t fd, const char *buf, intptr_t nbytes) { intptr_t result = 0; char stackBuf[512]; char *bufStart = NULL; uintptr_t outBufLen = sizeof(stackBuf); iconv_t converter = J9VM_INVALID_ICONV_DESCRIPTOR; size_t inbytesleft = 0; size_t outbytesleft = 0; char *inbuf = NULL; char *outbuf = NULL; intptr_t bytesToWrite = 0; #ifdef J9ZOS390 /* LIR 1280 (z/OS only) - every failed call to iconv_open() is recorded on the operator console, so don't retry */ if (FALSE == PPG_file_text_iconv_open_failed) { /* iconv_get is not an a2e function, so we need to pass it honest-to-goodness EBCDIC strings */ #pragma convlit(suspend) #endif #ifndef OMRZTPF converter = iconv_get(portLibrary, J9FILETEXT_ICONV_DESCRIPTOR, nl_langinfo(CODESET), "UTF-8"); #else converter = iconv_get(portLibrary, J9FILETEXT_ICONV_DESCRIPTOR, "IBM1047", "ISO8859-1" ); #endif #ifdef J9ZOS390 #pragma convlit(resume) if (J9VM_INVALID_ICONV_DESCRIPTOR == converter) { PPG_file_text_iconv_open_failed = TRUE; } } #endif if (J9VM_INVALID_ICONV_DESCRIPTOR == converter) { /* no converter available for this code set. Just dump the UTF-8 chars */ result = portLibrary->file_write(portLibrary, fd, (void *)buf, nbytes); return (result == nbytes) ? 0 : result; } inbuf = (char *)buf; /* for some reason this argument isn't const */ outbuf = bufStart = stackBuf; inbytesleft = nbytes; outbytesleft = sizeof(stackBuf); while ((size_t)-1 == iconv(converter, &inbuf, &inbytesleft, &outbuf, &outbytesleft)) { int tmp_errno = errno; if (inbytesleft == 0) { break; } if ((outbytesleft == 0) || (tmp_errno == E2BIG)) { /* input conversion stopped due to lack of space in the output buffer */ if (growBuffer(portLibrary, stackBuf, &bufStart, &outbuf, &outbytesleft, &outBufLen) < 0) { /* failed to grow buffer, just output what we've got so far */ break; } } else if (tmp_errno == EILSEQ) { /* input conversion stopped due to an input byte that does not belong to the input code set */ const char *unicodeFormat = "\\u%04x"; #define J9FILETEXT_ESCAPE_STR_SIZE 6 /* max size of unicode format */ char escapedStr[J9FILETEXT_ESCAPE_STR_SIZE]; char *escapedStrStart = escapedStr; uint16_t unicodeC = 0; size_t escapedLength = 0; size_t utf8Length = decodeUTF8CharN((const uint8_t *)inbuf, &unicodeC, inbytesleft); if (utf8Length == 0) { /* invalid encoding, including 4-byte UTF-8 */ utf8Length = 1; escapedLength = 1; escapedStr[0] = '?'; } else { escapedLength = portLibrary->str_printf(portLibrary, escapedStr, J9FILETEXT_ESCAPE_STR_SIZE, unicodeFormat, (uintptr_t)unicodeC); } inbytesleft -= utf8Length; inbuf += utf8Length; if ((size_t)-1 == iconv(converter, &escapedStrStart, &escapedLength, &outbuf, &outbytesleft)) { /* not handling EILSEQ here because: * 1. we can't do much if iconv() fails to convert ascii. * 2. inbuf and inbytesleft have been explicitly updated so the while loop will get terminated after converting the rest of the characters. */ tmp_errno = errno; /* if the remaining outbuf is too small, then grow it before storing Unicode string representation */ if (tmp_errno == E2BIG) { if (growBuffer(portLibrary, stackBuf, &bufStart, &outbuf, &outbytesleft, &outBufLen) < 0) { /* failed to grow buffer, just output what we've got so far */ break; } } } } else { /* input conversion stopped due to an incomplete character or shift sequence at the end of the input buffer */ break; } } iconv_free(portLibrary, J9FILETEXT_ICONV_DESCRIPTOR, converter); /* CMVC 152575 - the converted string is not necessarily the same length in bytes as the original string */ bytesToWrite = outbuf - bufStart; result = portLibrary->file_write(portLibrary, fd, (void *)bufStart, bytesToWrite); if (bufStart != stackBuf) { portLibrary->mem_free_memory(portLibrary, bufStart); } return (result == bytesToWrite) ? 0 : result; }