Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. #include <ctype.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. /* These two are for htonl / ntohl */
  6. #include <arpa/inet.h>
  7. #include <netinet/in.h>
  8.  
  9. #include <parserutils/charset/codec.h>
  10.  
  11. #include "utils/utils.h"
  12.  
  13. #include "testutils.h"
  14.  
  15. typedef struct line_ctx {
  16.         parserutils_charset_codec *codec;
  17.  
  18.         size_t buflen;
  19.         size_t bufused;
  20.         uint8_t *buf;
  21.         size_t explen;
  22.         size_t expused;
  23.         uint8_t *exp;
  24.  
  25.         bool indata;
  26.         bool inexp;
  27.  
  28.         parserutils_error exp_ret;
  29.  
  30.         enum { ENCODE, DECODE, BOTH } dir;
  31. } line_ctx;
  32.  
  33. static bool handle_line(const char *data, size_t datalen, void *pw);
  34. static void run_test(line_ctx *ctx);
  35.  
  36. static void *myrealloc(void *ptr, size_t len, void *pw)
  37. {
  38.         UNUSED(pw);
  39.  
  40.         return realloc(ptr, len);
  41. }
  42.  
  43. int main(int argc, char **argv)
  44. {
  45.         parserutils_charset_codec *codec;
  46.         line_ctx ctx;
  47.  
  48.         if (argc != 2) {
  49.                 printf("Usage: %s <filename>\n", argv[0]);
  50.                 return 1;
  51.         }
  52.  
  53.         assert(parserutils_charset_codec_create("NATS-SEFI-ADD",
  54.                         myrealloc, NULL, &codec) == PARSERUTILS_BADENCODING);
  55.  
  56.         assert(parserutils_charset_codec_create("UTF-16", myrealloc, NULL,
  57.                         &ctx.codec) == PARSERUTILS_OK);
  58.  
  59.         ctx.buflen = parse_filesize(argv[1]);
  60.         if (ctx.buflen == 0)
  61.                 return 1;
  62.  
  63.         ctx.buf = malloc(ctx.buflen);
  64.         if (ctx.buf == NULL) {
  65.                 printf("Failed allocating %u bytes\n", (int) ctx.buflen);
  66.                 return 1;
  67.         }
  68.  
  69.         ctx.exp = malloc(ctx.buflen);
  70.         if (ctx.exp == NULL) {
  71.                 printf("Failed allocating %u bytes\n", (int) ctx.buflen);
  72.                 free(ctx.buf);
  73.                 return 1;
  74.         }
  75.         ctx.explen = ctx.buflen;
  76.  
  77.         ctx.buf[0] = '\0';
  78.         ctx.exp[0] = '\0';
  79.         ctx.bufused = 0;
  80.         ctx.expused = 0;
  81.         ctx.indata = false;
  82.         ctx.inexp = false;
  83.         ctx.exp_ret = PARSERUTILS_OK;
  84.  
  85.         assert(parse_testfile(argv[1], handle_line, &ctx) == true);
  86.  
  87.         /* and run final test */
  88.         if (ctx.bufused > 0 && ctx.buf[ctx.bufused - 1] == '\n')
  89.                 ctx.bufused -= 1;
  90.  
  91.         if (ctx.expused > 0 && ctx.exp[ctx.expused - 1] == '\n')
  92.                 ctx.expused -= 1;
  93.  
  94.         run_test(&ctx);
  95.  
  96.         free(ctx.buf);
  97.  
  98.         parserutils_charset_codec_destroy(ctx.codec);
  99.  
  100.         printf("PASS\n");
  101.  
  102.         return 0;
  103. }
  104.  
  105. /**
  106.  * Converts hex character ('0' ... '9' or 'a' ... 'f' or 'A' ... 'F') to
  107.  * digit value.
  108.  * \param hex Valid hex character
  109.  * \return Corresponding digit value.
  110.  */
  111. static inline int hex2digit(char hex)
  112. {
  113.         return (hex <= '9') ? hex - '0' : (hex | 0x20) - 'a' + 10;
  114. }
  115.  
  116. bool handle_line(const char *data, size_t datalen, void *pw)
  117. {
  118.         line_ctx *ctx = (line_ctx *) pw;
  119.  
  120.         if (data[0] == '#') {
  121.                 if (ctx->inexp) {
  122.                         /* This marks end of testcase, so run it */
  123.  
  124.                         if (ctx->buf[ctx->bufused - 1] == '\n')
  125.                                 ctx->bufused -= 1;
  126.  
  127.                         if (ctx->exp[ctx->expused - 1] == '\n')
  128.                                 ctx->expused -= 1;
  129.  
  130.                         run_test(ctx);
  131.  
  132.                         ctx->buf[0] = '\0';
  133.                         ctx->exp[0] = '\0';
  134.                         ctx->bufused = 0;
  135.                         ctx->expused = 0;
  136.                         ctx->exp_ret = PARSERUTILS_OK;
  137.                 }
  138.  
  139.                 if (strncasecmp(data+1, "data", 4) == 0) {
  140.                         parserutils_charset_codec_optparams params;
  141.                         const char *ptr = data + 6;
  142.  
  143.                         ctx->indata = true;
  144.                         ctx->inexp = false;
  145.  
  146.                         if (strncasecmp(ptr, "decode", 6) == 0)
  147.                                 ctx->dir = DECODE;
  148.                         else if (strncasecmp(ptr, "encode", 6) == 0)
  149.                                 ctx->dir = ENCODE;
  150.                         else
  151.                                 ctx->dir = BOTH;
  152.  
  153.                         ptr += 7;
  154.  
  155.                         if (strncasecmp(ptr, "LOOSE", 5) == 0) {
  156.                                 params.error_mode.mode =
  157.                                         PARSERUTILS_CHARSET_CODEC_ERROR_LOOSE;
  158.                                 ptr += 6;
  159.                         } else if (strncasecmp(ptr, "STRICT", 6) == 0) {
  160.                                 params.error_mode.mode =
  161.                                         PARSERUTILS_CHARSET_CODEC_ERROR_STRICT;
  162.                                 ptr += 7;
  163.                         } else {
  164.                                 params.error_mode.mode =
  165.                                         PARSERUTILS_CHARSET_CODEC_ERROR_TRANSLIT;
  166.                                 ptr += 9;
  167.                         }
  168.  
  169.                         assert(parserutils_charset_codec_setopt(ctx->codec,
  170.                                 PARSERUTILS_CHARSET_CODEC_ERROR_MODE,
  171.                                 (parserutils_charset_codec_optparams *) &params)
  172.                                 == PARSERUTILS_OK);
  173.                 } else if (strncasecmp(data+1, "expected", 8) == 0) {
  174.                         ctx->indata = false;
  175.                         ctx->inexp = true;
  176.  
  177.                         ctx->exp_ret = parserutils_error_from_string(data + 10,
  178.                                         datalen - 10 - 1 /* \n */);
  179.                 } else if (strncasecmp(data+1, "reset", 5) == 0) {
  180.                         ctx->indata = false;
  181.                         ctx->inexp = false;
  182.  
  183.                         parserutils_charset_codec_reset(ctx->codec);
  184.                 }
  185.         } else {
  186.                 if (ctx->indata) {
  187.                         /* Process "&#xNNNN" as 16-bit code units.  */
  188.                         while (datalen) {
  189.                                 uint16_t nCodePoint;
  190.  
  191.                                 if (data[0] == '\n') {
  192.                                         ctx->buf[ctx->bufused++] = *data++;
  193.                                         --datalen;
  194.                                         continue;
  195.                                 }
  196.                                 assert(datalen >= sizeof ("&#xNNNN")-1 \
  197.                                         && data[0] == '&' && data[1] == '#' \
  198.                                         && data[2] == 'x' && isxdigit(data[3]) \
  199.                                         && isxdigit(data[4]) && isxdigit(data[5]) \
  200.                                         && isxdigit(data[6]));
  201.                                 /* UTF-16 code is always host endian (different
  202.                                    than UCS-32 !).  */
  203.                                 nCodePoint = (hex2digit(data[3]) << 12) |
  204.                                                 (hex2digit(data[4]) <<  8) |
  205.                                                 (hex2digit(data[5]) <<  4) |
  206.                                                 hex2digit(data[6]);
  207.                                 *((uint16_t *) (void *) (ctx->buf + ctx->bufused)) =
  208.                                                 nCodePoint;
  209.                                 ctx->bufused += 2;
  210.                                 data += sizeof ("&#xNNNN")-1;
  211.                                 datalen -= sizeof ("&#xNNNN")-1;
  212.                         }
  213.                 }
  214.                 if (ctx->inexp) {
  215.                         /* Process "&#xXXXXYYYY as 32-bit code units.  */
  216.                         while (datalen) {
  217.                                 uint32_t nCodePoint;
  218.  
  219.                                 if (data[0] == '\n') {
  220.                                         ctx->exp[ctx->expused++] = *data++;
  221.                                         --datalen;
  222.                                         continue;
  223.                                 }
  224.                                 assert(datalen >= sizeof ("&#xXXXXYYYY")-1 \
  225.                                         && data[0] == '&' && data[1] == '#' \
  226.                                         && data[2] == 'x' && isxdigit(data[3]) \
  227.                                         && isxdigit(data[4]) && isxdigit(data[5]) \
  228.                                         && isxdigit(data[6]) && isxdigit(data[7]) \
  229.                                         && isxdigit(data[8]) && isxdigit(data[9]) \
  230.                                         && isxdigit(data[10]));
  231.                                 /* UCS-4 code is always big endian, so convert
  232.                                    host endian to big endian.  */
  233.                                 nCodePoint =
  234.                                         htonl((hex2digit(data[3]) << 28)
  235.                                         | (hex2digit(data[4]) << 24)
  236.                                         | (hex2digit(data[5]) << 20)
  237.                                         | (hex2digit(data[6]) << 16)
  238.                                         | (hex2digit(data[7]) << 12)
  239.                                         | (hex2digit(data[8]) << 8)
  240.                                         | (hex2digit(data[9]) << 4)
  241.                                         | hex2digit(data[10]));
  242.                                 *((uint32_t *) (void *) (ctx->exp + ctx->expused)) =
  243.                                                 nCodePoint;
  244.                                 ctx->expused += 4;
  245.                                 data += sizeof ("&#xXXXXYYYY")-1;
  246.                                 datalen -= sizeof ("&#xXXXXYYYY")-1;
  247.                         }
  248.                 }
  249.         }
  250.  
  251.         return true;
  252. }
  253.  
  254. void run_test(line_ctx *ctx)
  255. {
  256.         static int testnum;
  257.         size_t destlen = ctx->bufused * 4;
  258.         uint8_t *dest = alloca(destlen);
  259.         uint8_t *pdest = dest;
  260.         const uint8_t *psrc = ctx->buf;
  261.         size_t srclen = ctx->bufused;
  262.         size_t i;
  263.  
  264.         if (ctx->dir == DECODE) {
  265.                 assert(parserutils_charset_codec_decode(ctx->codec,
  266.                                 &psrc, &srclen,
  267.                                 &pdest, &destlen) == ctx->exp_ret);
  268.         } else if (ctx->dir == ENCODE) {
  269.                 assert(parserutils_charset_codec_encode(ctx->codec,
  270.                                 &psrc, &srclen,
  271.                                 &pdest, &destlen) == ctx->exp_ret);
  272.         } else {
  273.                 size_t templen = ctx->bufused * 4;
  274.                 uint8_t *temp = alloca(templen);
  275.                 uint8_t *ptemp = temp;
  276.                 const uint8_t *ptemp2;
  277.                 size_t templen2;
  278.  
  279.                 assert(parserutils_charset_codec_decode(ctx->codec,
  280.                                 &psrc, &srclen,
  281.                                 &ptemp, &templen) == ctx->exp_ret);
  282.                 /* \todo currently there is no way to specify the number of
  283.                    consumed & produced data in case of a deliberate bad input
  284.                    data set.  */
  285.                 if (ctx->exp_ret == PARSERUTILS_OK) {
  286.                         assert(temp + (ctx->bufused * 4 - templen) == ptemp);
  287.                 }
  288.  
  289.                 ptemp2 = temp;
  290.                 templen2 = ctx->bufused * 4 - templen;
  291.                 assert(parserutils_charset_codec_encode(ctx->codec,
  292.                                 &ptemp2, &templen2,
  293.                                 &pdest, &destlen) == ctx->exp_ret);
  294.                 if (ctx->exp_ret == PARSERUTILS_OK) {
  295.                         assert(templen2 == 0);
  296.                         assert(temp + (ctx->bufused * 4 - templen) == ptemp2);
  297.                 }
  298.         }
  299.         if (ctx->exp_ret == PARSERUTILS_OK) {
  300.                 assert(srclen == 0);
  301.                 assert(ctx->buf + ctx->bufused == psrc);
  302.                 assert(dest + (ctx->bufused * 4 - destlen) == pdest);
  303.                 assert(ctx->bufused * 4 - destlen == ctx->expused);
  304.         }
  305.  
  306.         printf("%d: Read '", ++testnum);
  307.         for (i = 0; i < ctx->expused; i++) {
  308.                 printf("%c%c ", "0123456789abcdef"[(dest[i] >> 4) & 0xf],
  309.                                 "0123456789abcdef"[dest[i] & 0xf]);
  310.         }
  311.         printf("' Expected '");
  312.         for (i = 0; i < ctx->expused; i++) {
  313.                 printf("%c%c ", "0123456789abcdef"[(ctx->exp[i] >> 4) & 0xf],
  314.                                 "0123456789abcdef"[ctx->exp[i] & 0xf]);
  315.         }
  316.         printf("'\n");
  317.  
  318.         assert(pdest == dest + ctx->expused);
  319.         assert(memcmp(dest, ctx->exp, ctx->expused) == 0);
  320. }
  321.  
  322.