#include <errno.h>
#include <iconv.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
/* The various invalid sequences can be inferred from the table of
* (d) 0xC0, 0xC1, 0xF5-0xFF are never valid
*/
+#define ASCII_MAX 0x7F
+#define MULTIBYTE_MIN 0xC3
+
#define SUCCESS 0
#define FAILURE 1
return FAILURE;
}
-
return SUCCESS;
}
printf("iconv_open() does not support invalid \"from\" codeset...");
iconv_t cd = iconv_open(tocode, fromcode);
if (cd == (iconv_t)(-1)) {
- switch (errno) {
- case EINVAL:
- printf("OK (EINVAL, expected)\n");
- return SUCCESS;
- default:
- printf("FAIL (errno=%d, unexpected)\n", errno);
- return FAILURE;
+ if (errno == EINVAL) {
+ printf("OK (EINVAL, expected)\n");
+ return SUCCESS;
+ }
+ else {
+ printf("FAIL (errno=%d, unexpected)\n", errno);
+ return FAILURE;
}
}
printf("FAIL (invalid codeset was accepted)\n");
return FAILURE;
}
+/* If a sequence of input bytes does not form a valid character or
+ * shift sequence in the input codeset... conversion shall stop after
+ * the previous successfully converted character or shift sequence.
+ *
+ *
+ * [EILSEQ]
+ * Input conversion stopped due to an input byte that does not belong
+ * to the input codeset.
+ */
+int test_iconv_invalid_char_is_eilseq() {
+ iconv_t cd;
+ const char* tocode = "ASCII";
+
+ printf("iconv() returns EILSEQ on invalid input...");
+ if (_my_iconv_open(&cd, tocode, tocode) == FAILURE) {
+ printf("ERROR (iconv_open)\n");
+ return FAILURE;
+ }
+
+ size_t insize = 1, outsize = 1;
+ char* inbuf = (char*)malloc(insize);
+ char* outbuf = (char*)malloc(outsize);
+
+ inbuf[0] = ASCII_MAX + 1; // not ascii
+
+ size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize);
+
+ if (result == (size_t)(-1)) {
+ int saved_errno = errno; // iconv_close() clobbers it
+
+ if (_my_iconv_close(&cd) == FAILURE) {
+ printf("ERROR (iconv_close)\n");
+ return FAILURE;
+ }
+
+ if (saved_errno == EILSEQ) {
+ printf("OK (EILSEQ, expected)\n");
+ return SUCCESS;
+ }
+ else {
+ printf("FAIL (errno=%d, unexpected)\n", saved_errno);
+ return FAILURE;
+ }
+ }
+
+ printf("FAIL (no error)\n");
+ return FAILURE;
+}
+
+/* If the input buffer ends with an incomplete character or shift
+ * sequence, conversion shall stop after the previous successfully
+ * converted bytes.
+ *
+ * [EINVAL]
+ * Input conversion stopped due to an incomplete character or shift
+ * sequence at the end of the input buffer.
+ */
+int test_iconv_incomplete_multibyte_is_einval() {
+ iconv_t cd;
+ const char* tocode = "UTF-8";
+
+ printf("iconv() returns EINVAL on incomplete multibyte...");
+ if (_my_iconv_open(&cd, tocode, tocode) == FAILURE) {
+ printf("ERROR (iconv_open)\n");
+ return FAILURE;
+ }
+
+ size_t insize = 1, outsize = 1;
+ char* inbuf = (char*)malloc(insize);
+ char* outbuf = (char*)malloc(outsize);
+
+ // a single byte in the input buffer that demands
+ // a (nonexistent) subsequent byte
+ inbuf[0] = MULTIBYTE_MIN;
+
+ size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize);
+
+ if (result == (size_t)(-1)) {
+ int saved_errno = errno; // iconv_close() clobbers it
+
+ if (_my_iconv_close(&cd) == FAILURE) {
+ printf("ERROR (iconv_close)\n");
+ return FAILURE;
+ }
+
+ if (saved_errno == EINVAL) {
+ printf("OK (EINVAL, expected)\n");
+ return SUCCESS;
+ }
+ else {
+ printf("FAIL (errno=%d, unexpected)\n", saved_errno);
+ return FAILURE;
+ }
+ }
+
+ printf("FAIL (no error)\n");
+ return FAILURE;
+}
+
+int test_iconv_too_big_is_e2big() {
+ iconv_t cd;
+ const char* tocode = "ASCII";
+
+ printf("iconv() returns E2BIG if the input is too big...");
+ if (_my_iconv_open(&cd, tocode, tocode) == FAILURE) {
+ printf("ERROR (iconv_open)\n");
+ return FAILURE;
+ }
+
+ size_t insize = 2, outsize = 1;
+ char* inbuf = (char*)malloc(insize);
+ char* outbuf = (char*)malloc(outsize);
+
+ // a single byte in the input buffer that demands
+ // a (nonexistent) subsequent byte
+ inbuf[0] = 'h';
+ inbuf[1] = 'i';
+
+ size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize);
+
+ if (result == (size_t)(-1)) {
+ int saved_errno = errno; // iconv_close() clobbers it
+
+ if (_my_iconv_close(&cd) == FAILURE) {
+ printf("ERROR (iconv_close)\n");
+ return FAILURE;
+ }
+
+ if (saved_errno == E2BIG) {
+ printf("OK (E2BIG, expected)\n");
+ return SUCCESS;
+ }
+ else {
+ printf("FAIL (errno=%d, unexpected)\n", saved_errno);
+ return FAILURE;
+ }
+ }
+
+ printf("FAIL (no error)\n");
+ return FAILURE;
+}
+
int main(int argc, char** argv) {
int result = test_open_close();
result |= test_iconv_open_does_not_support_invalid_to_codeset();
result |= test_iconv_open_does_not_support_invalid_from_codeset();
+ result |= test_iconv_invalid_char_is_eilseq();
+ result |= test_iconv_too_big_is_e2big();
+ result |= test_iconv_incomplete_multibyte_is_einval();
+
return result;
}