wsutf8.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:8k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * wsutf8.c
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  *
  7.  * Copyright (c) 1999-2000 WAPIT OY LTD.
  8.  *  All rights reserved.
  9.  *
  10.  * Functions to manipulate UTF-8 encoded strings.
  11.  *
  12.  * Specification: RFC-2279
  13.  *
  14.  */
  15. #include "wsint.h"
  16. /********************* Types and definitions ****************************/
  17. /* Masks to determine the UTF-8 encoding of an ISO 10646 character. */
  18. #define WS_UTF8_ENC_1_M 0xffffff80
  19. #define WS_UTF8_ENC_2_M 0xfffff800
  20. #define WS_UTF8_ENC_3_M 0xffff0000
  21. #define WS_UTF8_ENC_4_M 0xffe00000
  22. #define WS_UTF8_ENC_5_M 0xfc000000
  23. #define WS_UTF8_ENC_6_M 0x80000000
  24. /* The high-order bits.  This array can be indexed with the number of
  25.    bytes in the encoding to get the initialization mask for the
  26.    high-order bits. */
  27. static unsigned char utf8_hibits[7] =
  28.     {
  29.         0x00,  /* unused */
  30.         0x00,  /* 1 byte */
  31.         0xc0,  /* 2 bytes */
  32.         0xe0,  /* 3 bytes */
  33.         0xf0,  /* 4 bytes */
  34.         0xf8,  /* 5 bytes */
  35.         0xfc,  /* 6 bytes */
  36.     };
  37. /* The high-order bits for continuation bytes (10xxxxxx). */
  38. #define WS_UTF8_ENC_C_BITS 0x80
  39. /* Mask to get the continuation bytes from the character (00111111). */
  40. #define WS_UTF8_CONT_DATA_MASK 0x3f
  41. /* Determine the encoding type of the ISO 10646 character `ch'.  The
  42.    argument `ch' must be given as `unsigned long'.  The macro returns
  43.    0 if the value `ch' can not be encoded as UTF-8 and the number of
  44.    bytes in the encoded value otherwise. */
  45. #define WS_UTF8_ENC_TYPE(ch)
  46.     (((ch) & WS_UTF8_ENC_1_M) == 0
  47.      ? 1
  48.      : (((ch) & WS_UTF8_ENC_2_M) == 0
  49.        ? 2
  50.        : (((ch) & WS_UTF8_ENC_3_M) == 0
  51.          ? 3
  52.          : (((ch) & WS_UTF8_ENC_4_M) == 0
  53.            ? 4
  54.            : (((ch) & WS_UTF8_ENC_5_M) == 0
  55.              ? 5
  56.              : (((ch) & WS_UTF8_ENC_6_M) == 0   
  57.                ? 6
  58.                : 0))))))
  59. /* Masks and values to determine the length of an UTF-8 encoded
  60.    character. */
  61. #define WS_UTF8_DEC_1_M 0x80
  62. #define WS_UTF8_DEC_2_M 0xe0
  63. #define WS_UTF8_DEC_3_M 0xf0
  64. #define WS_UTF8_DEC_4_M 0xf8
  65. #define WS_UTF8_DEC_5_M 0xfc
  66. #define WS_UTF8_DEC_6_M 0xfe
  67. #define WS_UTF8_DEC_1_V 0x00
  68. #define WS_UTF8_DEC_2_V 0xc0
  69. #define WS_UTF8_DEC_3_V 0xe0
  70. #define WS_UTF8_DEC_4_V 0xf0
  71. #define WS_UTF8_DEC_5_V 0xf8
  72. #define WS_UTF8_DEC_6_V 0xfc
  73. /* Masks to get the data bits from the first byte of an UTF-8 encoded
  74.    character.  This array can be indexed with the number of bytes in
  75.    the encoding. */
  76. static unsigned char utf8_hidata_masks[7] =
  77.     {
  78.         0x00,  /* unused */
  79.         0x7f,  /* 1 byte */
  80.         0x1f,  /* 2 bytes */
  81.         0x0f,  /* 3 bytes */
  82.         0x07,  /* 4 bytes */
  83.         0x03,  /* 5 bytes */
  84.         0x01,  /* 6 bytes */
  85.     };
  86. /* The mask and the value of the continuation bytes. */
  87. #define WS_UTF8_DEC_C_M 0xc0
  88. #define WS_UTF8_DEC_C_V 0x80
  89. /* Determine how many bytes the UTF-8 encoding uses by investigating
  90.    the first byte `b'.  The argument `b' must be given as `unsigned
  91.    char'.  The macro returns 0 if the byte `b' is not a valid UTF-8
  92.    first byte. */
  93. #define WS_UTF8_DEC_TYPE(b)
  94.     (((b) & WS_UTF8_DEC_1_M) == WS_UTF8_DEC_1_V
  95.      ? 1
  96.      : (((b) & WS_UTF8_DEC_2_M) == WS_UTF8_DEC_2_V
  97.        ? 2
  98.        : (((b) & WS_UTF8_DEC_3_M) == WS_UTF8_DEC_3_V
  99.          ? 3
  100.          : (((b) & WS_UTF8_DEC_4_M) == WS_UTF8_DEC_4_V
  101.            ? 4
  102.            : (((b) & WS_UTF8_DEC_5_M) == WS_UTF8_DEC_5_V
  103.              ? 5
  104.              : (((b) & WS_UTF8_DEC_6_M) == WS_UTF8_DEC_6_V
  105.                ? 6
  106.                : 0))))))
  107. /* Predicate to check whether the `unsigned char' byte `b' is a
  108.    continuation byte. */
  109. #define WS_UTF8_DEC_C_P(b) (((b) & WS_UTF8_DEC_C_M) == WS_UTF8_DEC_C_V)
  110. /********************* Global functions *********************************/
  111. WsUtf8String *ws_utf8_alloc()
  112. {
  113.     return ws_calloc(1, sizeof(WsUtf8String));
  114. }
  115. void ws_utf8_free(WsUtf8String *string)
  116. {
  117.     if (string == NULL)
  118.         return;
  119.     ws_free(string->data);
  120.     ws_free(string);
  121. }
  122. int ws_utf8_append_char(WsUtf8String *string, unsigned long ch)
  123. {
  124.     unsigned char *d;
  125.     unsigned int num_bytes = WS_UTF8_ENC_TYPE(ch);
  126.     unsigned int len, i;
  127.     if (num_bytes == 0)
  128.         ws_fatal("ws_utf8_append_char(): 0x%lx is not a valid UTF-8 character",
  129.                  ch);
  130.     d = ws_realloc(string->data, string->len + num_bytes);
  131.     if (d == NULL)
  132.         return 0;
  133.     len = string->len;
  134.     /* Encode the continuation bytes (n > 1). */
  135.     for (i = num_bytes - 1; i > 0; i--) {
  136.         d[len + i] = WS_UTF8_ENC_C_BITS;
  137.         d[len + i] |= ch & WS_UTF8_CONT_DATA_MASK;
  138.         ch >>= 6;
  139.     }
  140.     /* And continue the first byte. */
  141.     d[len] = utf8_hibits[num_bytes];
  142.     d[len] |= ch;
  143.     string->data = d;
  144.     string->len += num_bytes;
  145.     string->num_chars++;
  146.     return 1;
  147. }
  148. int ws_utf8_verify(const unsigned char *data, size_t len,
  149.                    size_t *strlen_return)
  150. {
  151.     unsigned int num_bytes, i;
  152.     size_t strlen = 0;
  153.     while (len > 0) {
  154.         num_bytes = WS_UTF8_DEC_TYPE(*data);
  155.         if (num_bytes == 0)
  156.             /* Not a valid beginning. */
  157.             return 0;
  158.         if (len < num_bytes)
  159.             /* The data is truncated. */
  160.             return 0;
  161.         for (i = 1; i < num_bytes; i++)
  162.             if (!WS_UTF8_DEC_C_P(data[i]))
  163.                 /* Not a valid continuation byte. */
  164.                 return 0;
  165.         len -= num_bytes;
  166.         data += num_bytes;
  167.         strlen++;
  168.     }
  169.     if (strlen_return)
  170.         *strlen_return = strlen;
  171.     return 1;
  172. }
  173. int ws_utf8_set_data(WsUtf8String *string, const unsigned char *data,
  174.                      size_t len)
  175. {
  176.     size_t num_chars;
  177.     if (!ws_utf8_verify(data, len, &num_chars))
  178.         /* Malformed data. */
  179.         return 0;
  180.     /* Init `string' to empty. */
  181.     ws_free(string->data);
  182.     string->data = NULL;
  183.     string->len = 0;
  184.     string->num_chars = 0;
  185.     /* Set the new data. */
  186.     string->data = ws_memdup(data, len);
  187.     if (string->data == NULL)
  188.         return 0;
  189.     string->len = len;
  190.     string->num_chars = num_chars;
  191.     return 1;
  192. }
  193. int ws_utf8_get_char(const WsUtf8String *string, unsigned long *ch_return,
  194.                      size_t *posp)
  195. {
  196.     size_t pos = *posp;
  197.     unsigned int num_bytes, i;
  198.     unsigned char *data;
  199.     unsigned long ch;
  200.     if (pos < 0 || pos >= string->len)
  201.         /* Index out range. */
  202.         return 0;
  203.     data = string->data + pos;
  204.     num_bytes = WS_UTF8_DEC_TYPE(*data);
  205.     if (num_bytes == 0)
  206.         /* Invalid position. */
  207.         return 0;
  208.     if (pos + num_bytes > string->len)
  209.         /* Truncated data. */
  210.         return 0;
  211.     /* Get the first byte. */
  212.     ch = data[0] & utf8_hidata_masks[num_bytes];
  213.     /* Add the continuation bytes. */
  214.     for (i = 1; i < num_bytes; i++) {
  215.         ch <<= 6;
  216.         ch |= data[i] & WS_UTF8_CONT_DATA_MASK;
  217.     }
  218.     *ch_return = ch;
  219.     *posp = pos + num_bytes;
  220.     return 1;
  221. }
  222. unsigned char *ws_utf8_to_latin1(const WsUtf8String *string,
  223.                                  unsigned char unknown_char,
  224.                                  size_t *len_return)
  225. {
  226.     unsigned char *cstr;
  227.     size_t i;
  228.     size_t pos = 0;
  229.     if (string == NULL)
  230.         return NULL;
  231.     cstr = ws_malloc(string->num_chars + 1);
  232.     if (cstr == NULL)
  233.         return NULL;
  234.     for (i = 0; i < string->num_chars; i++) {
  235.         unsigned long ch;
  236.         if (!ws_utf8_get_char(string, &ch, &pos))
  237.             ws_fatal("ws_utf8_to_latin1_cstr(): internal inconsistency");
  238.         if (ch > 0xff)
  239.             cstr[i] = unknown_char;
  240.         else
  241.             cstr[i] = (unsigned char) ch;
  242.     }
  243.     cstr[i] = '';
  244.     if (len_return)
  245.         *len_return = string->num_chars;
  246.     return cstr;
  247. }
  248. void ws_utf8_free_data(unsigned char *data)
  249. {
  250.     if (data)
  251.         ws_free(data);
  252. }