Advertisement
avp210159

ucsutf.c

Feb 24th, 2014
670
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.88 KB | None | 0 0
  1. /*
  2.   ucsutf.c  avp 2012
  3.  
  4.   Функции для UTF-8 и Unicode (ASCII&Cyrillic), независимые от setlocale()
  5.  */
  6.  
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #include <errno.h>
  13.  
  14. #include "ucsutf.h"
  15.  
  16. /*
  17.   utf-8 схема                                               error: 0xFF, 0xFE
  18.   1111 110x , 1111 10xx , 1111 0xxx , 1110 xxxx , 110x xxxx , 10xx xxxx
  19.   10xx xxxx , 10xx xxxx , 10xx xxxx , 10xx xxxx , 10xx xxxx
  20.   10xx xxxx , 10xx xxxx , 10xx xxxx , 10xx xxxx
  21.   10xx xxxx , 10xx xxxx , 10xx xxxx
  22.   10xx xxxx , 10xx xxxx
  23.   10xx xxxx
  24. */
  25. // значимые биты из первого байта UTF-8
  26. static int mask[5] = { 0x01, 0x03 ,0x07 ,0x0F ,0x1F};
  27.  
  28. int
  29. ucs_len (int ucs)
  30. {
  31.   if (ucs < 0)
  32.     return 0;
  33.   if (ucs < 128)
  34.     return 1;
  35.   int n = 6;
  36.   if (ucs < 0x800)
  37.     n = 2;
  38.   else if (ucs < 0x10000)
  39.     n = 3;
  40.   else if (ucs < 0x200000)
  41.     n = 4;
  42.   else if (ucs < 0x4000000)
  43.     n = 5;
  44.   return n;
  45. }
  46.  
  47.  
  48. /*
  49.   Некая замена fgetwc()
  50.   не зависит от setlocale() и ПОЗВОЛЯЕТ использовать fgetc() и др.
  51.  
  52.   Возвращает UCS from stream UTF-8 characters or EOF
  53.   если преобразование UTF-8 -> UCS невозможно возвращает EOF
  54.   и устанавливает errno в EILSEQ
  55.  
  56.   Также заполняет структуру getucs прочитанными байтами
  57.  */
  58. int
  59. utf8_fgetc (struct getucs *uc, FILE *f)
  60. {
  61.   uc->nc = uc->err = 0;
  62.   int c, n = 5;
  63.   if (feof(f))
  64.     c = EOF;
  65.   else if ((c = fgetc(f)) != EOF) {
  66.     uc->bytes[uc->nc++] = c;
  67.     if (c > 127) {
  68.       if ((c & 0xc0) == 0x80 || c == 0xff || c == 0xfe) {
  69.     c = EOF;
  70.     uc->err = 1;
  71.       } else {
  72.     while (n && (c & (1<<n)))
  73.       n--;
  74.  
  75.     u_int ucs = c & mask[n-1];
  76.     n = 6-n;
  77.     while (n--) {
  78.       if ((c = fgetc(f)) == EOF)
  79.         break;
  80.       if (((uc->bytes[uc->nc++] = c) & 0xc0) != 0x80) {
  81.         uc->err = uc->nc;
  82.         c = EOF;
  83.         break;
  84.       }
  85.       ucs <<= 6;
  86.       ucs |= (c & 0x3f);
  87.     }
  88.     if (c != EOF)
  89.       c = ucs;
  90.       }
  91.     }
  92.   }
  93.   if (uc->err)
  94.     errno = EILSEQ;
  95.   return uc->ucs = c;
  96. }
  97.  
  98. /*
  99.   Получает адрес памяти с байтами, закодированными в UTF-8.
  100.   Возвращает UCS из одного или нескольких байт в памяти кодированных в UTF-8.
  101.   Во втором аргументе возвращает длину UTF-8 последовательности.
  102.   Третий аргумент индикатор ошибки. Если ошибки нет, то он устанавливается в 0.
  103.  
  104.   При ошибке (недопустимая UTF-8 последовательность)
  105.   возвращает первый байт, второй параметр устанавливается в 1,
  106.   а третий задает смещение к байту, следующего за ошибочным.
  107.  */
  108. int
  109. utf8_to_ucs (const char *utf, int *step, int *err)
  110. {
  111.   if (step)
  112.     *step = 1;
  113.   if (err)
  114.     *err = 0;
  115.   u_int ucs = *utf & 0xFF, estep = 1;
  116.   int k, n = 5, efl = 0;
  117.  
  118.   if (ucs > 127) {
  119.     // для любой длины utf-8
  120.     // FF, FE, 10xx xxxx в первом байте - error (not utf-8 !!!). Return it
  121.     if ((ucs & 0xC0) == 0x80 || ucs == 0xFF || ucs == 0xFE)
  122.       efl = 1;
  123.     else {
  124.       // 1111110x
  125.       while (n && (ucs & (1<<n)))
  126.     n--;
  127.  
  128.       k = 7-n;
  129.       u_int uc = ucs & mask[n-1];
  130.       n = 6-n;
  131.       while (n--) {
  132.     estep++;
  133.     if ((*(++utf) & 0xC0) != 0x80) {
  134.       efl = 1;
  135.       break;
  136.     }
  137.     uc <<= 6;
  138.     uc |= (*utf & 0x3f);
  139.       }
  140.       if (!efl) {
  141.     if (step)
  142.       *step = k;
  143.     ucs = uc;
  144.       }
  145.     }
  146.   }
  147.   if (efl) {
  148.     if (err)
  149.       *err = estep;
  150.     errno = EILSEQ;
  151.   }
  152.   return ucs;
  153. }
  154.  
  155. /*
  156.   Для заданного UCS помещает в память байты в UTF-8
  157.   Возвращает количество байт или 0 при ошибке (UCS < 0)
  158.  */
  159. int
  160. ucs_to_utf8 (int uc, char *b)
  161. {
  162.   if (uc < 0)
  163.     return 0;
  164.   u_int ucs = uc;
  165.   if (ucs < 128) {
  166.     b[0] = ucs;
  167.     return 1;
  168.   }
  169.  
  170.   int n = 6, i;
  171.   if (ucs < 0x800)
  172.     n = 2;
  173.   else if (ucs < 0x10000)
  174.     n = 3;
  175.   else if (ucs < 0x200000)
  176.     n = 4;
  177.   else if (ucs < 0x4000000)
  178.     n = 5;
  179.  
  180.   char *u = b+n-1;
  181.   static u_int
  182.     mask1[7] = { 0x0, 0x0, 0x1f, 0x0f, 0x07, 0x03, 0x01},
  183.     mask2[7] = { 0x0, 0x0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
  184.  
  185.   for (i = 0; i < n-1; i++, u--, ucs >>= 6)
  186.     *u = (ucs & 0x3f) | 0x80;
  187.   *u = (ucs & mask1[n]) | mask2[n];
  188.  
  189.   return n;
  190. }
  191.  
  192.  
  193. /*
  194.   Проверяет является ли байт началом символа в UTF-8
  195.   Возвращает
  196.   -1 - недопустимый символ (шаг назад)
  197.   n > 0 UTF-8 символ длиной n байт
  198.  */
  199. int
  200. utf8_chrlen (const char *utf)
  201. {
  202.   u_int ucs = *utf & 0xFF;
  203.  
  204.   if (ucs < 128)
  205.     return 1;
  206.   if ((ucs & 0xC0) == 0x80 || ucs == 0xFF || ucs == 0xFE)
  207.     return -1;
  208.  
  209.   int n = 5;
  210.   while (n && (ucs & (1<<n)))
  211.     n--;
  212.   return 7-n;
  213. }
  214.  
  215.  
  216. // ascii alpha or Cyr
  217. int
  218. isAlpha (int ucs)
  219. {
  220.   if ((u_int)ucs < 128)
  221.     return isalpha(ucs);
  222.   if (0x400 <= ucs && ucs < 0x460)
  223.     return 1;
  224.   return 0;
  225. }
  226.  
  227. int
  228. isLower (int ucs)
  229. {
  230.   if ((u_int)ucs < 128)
  231.     return islower(ucs);
  232.   if (0x430 <= ucs && ucs < 0x460)
  233.     return 1;
  234.   return 0;
  235. }
  236.  
  237. int
  238. isUpper (int ucs)
  239. {
  240.   if ((u_int)ucs < 128)
  241.     return isupper(ucs);
  242.   if (0x400 <= ucs && ucs < 0x430)
  243.     return 1;
  244.   return 0;
  245. }
  246.  
  247. int
  248. toLower (int ucs)
  249. {
  250.   if ((u_int)ucs < 128)
  251.     return tolower(ucs);
  252.   if (0x400 <= ucs && ucs < 0x410)
  253.     return ucs+80;
  254.   if (0x410 <= ucs && ucs < 0x430)
  255.     return ucs+32;
  256.   return ucs;
  257. }
  258.  
  259. // ascii alpha or only Rus
  260. int
  261. toUpper (int ucs)
  262. {
  263.   if ((u_int)ucs < 128)
  264.     return toupper(ucs);
  265.   if (0x430 <= ucs && ucs < 0x450)
  266.     return ucs-32;
  267.   if (0x450 <= ucs && ucs < 0x460)
  268.     return ucs-80;
  269.   return ucs;
  270. }
  271.  
  272. /*
  273.   utf8_toUpper(), utf8_toLower() меняет регистр UTF-8 символа "по месту"
  274.  
  275.   Возвращают длину измененного символа
  276.   При ошибке возвращают 0 и устанавливаеют параметр err в смещение к байту,
  277.   следующего за ошибочным.
  278.  */
  279. int
  280. utf8_toUpper (char *utf, int *err)
  281. {
  282.   u_int ucs = utf8_to_ucs(utf,0,err);
  283.   return *err? 0: ucs_to_utf8(toUpper(ucs), utf);
  284. }
  285.  
  286. int
  287. utf8_toLower (char *utf, int *err)
  288. {
  289.   u_int ucs = utf8_to_ucs(utf,0,err);
  290.   return *err? 0: ucs_to_utf8(toLower(ucs), utf);
  291. }
  292.  
  293. /*
  294.   Длина utf-8 в символах.
  295.  
  296.   Передаем адрес начала и размер в байтах. Если размер равен нулю,
  297.   то считаем до U+0000
  298.   При ошибке (неправильный utf-8) в *err передаем смещениие в байтах + 1
  299.  */
  300. int
  301. utf8_len (const char *utf, int n, int *err)
  302. {
  303.   int ucs = 1, step, nc = 0;
  304.   const char *s = utf;
  305.  
  306.   if (n) {
  307.     while (n > 0) {
  308.       ucs = utf8_to_ucs(utf,&step,err);
  309.       if (*err) {
  310.     *err += (utf-s);
  311.     break;
  312.       }
  313.       if ((n -= step) >= 0)
  314.     nc++;
  315.       utf += step;
  316.     }
  317.   } else {
  318.     while (ucs = utf8_to_ucs(utf,&step,err)) {
  319.       if (*err) {
  320.     *err += (utf-s);
  321.     break;
  322.       }
  323.       utf += step;
  324.       nc++;
  325.     }
  326.   }
  327.   return nc;
  328. }
  329.  
  330. /*
  331.   Перекодирует n байт строки из utf-8 в массив Unicode
  332.  
  333.   Если длина n == 0, то перекодируем до '\0' в utf
  334.   Возвращает количество символов UCS и в
  335.   *ofs смещение первого не обработанного в байтах в utf (при ошибке < 0)
  336. */
  337. int
  338. utf8str_to_ucs (const char *utf, int n,
  339.                int *ucsarr, int size, int *ofs)
  340. {
  341.   int ucs, nc = 0, step, err;
  342.   const char *s = utf;
  343.  
  344.   *ofs = 0;
  345.   if (n) {
  346.     while (nc < size && n > 0) {
  347.       ucs = utf8_to_ucs(utf,&step,&err);
  348.       if (err) {
  349.     *ofs = -(err + (utf-s));
  350.     break;
  351.       }
  352.       if ((n -= step) >= 0) {
  353.     ucsarr[nc++] = ucs;
  354.     *ofs += step;
  355.       }
  356.       utf += step;
  357.     }
  358.   } else {
  359.     while ((ucs = utf8_to_ucs(utf,&step,&err)) && nc < size) {
  360.       if (err) {
  361.     *ofs = -(err + (utf-s));
  362.     break;
  363.       }
  364.       utf += step;
  365.       *ofs += step;
  366.       ucsarr[nc++] = ucs;
  367.     }
  368.   }
  369.   return nc;
  370. }
  371.  
  372. // returns -1 if OK !!!
  373. int
  374. ucs_to_surrpair (u_int ucs, int sp[2])
  375. {
  376.   sp[0] = sp[1] = 0;
  377.   if (ucs < 0x10000 || ucs > 0x10FFFF)
  378.     return ucs;
  379.   sp[0] = ((ucs >> 10) & 0x3FF) | 0xD8;
  380.   sp[1] = (ucs & 0x3FF) | 0xDC;
  381.   return -1;
  382. }
  383.  
  384. // returns 0 if no valid surrogate pair
  385. int
  386. surpair_to_ucs (int sp[2])
  387. {
  388.   int ucs = 0;
  389.  
  390.   if ((sp[0] & 0xFFFFFC00) == 0xD800 && (sp[1] & 0xFFFFFC00) == 0xDC00)
  391.     ucs = ((sp[0] & 0x3FF) << 10) | (sp[1] & 0x3FF);
  392.   return ucs;
  393. }
  394.  
  395.  
  396. static inline int
  397. hexdigit (int c)
  398. {
  399.   if (c <= '9')
  400.     return c-'0';
  401.   if (c <= 'F')
  402.     return c-'A'+10;
  403.   return c-'a'+10;
  404. }
  405.  
  406.  
  407. /*
  408.   Возвращает UCS из строки
  409.   HHHH
  410.   если HHHH это первая часть суррогатной пары, то читает далее \uHHHH
  411.   в *step смещение от json.
  412.   при ошибке в *err смещение следующего за обнаруженной ошибкой байта
  413.  */
  414. static int
  415. getjhex (const char *json, const char *end, int *step, int *err)
  416. {
  417.   int i, ucs = 0;
  418.  
  419.   if (json+4 >= end) {
  420.     *err = end-json+1;
  421.     return 0;
  422.   }
  423.   *err = 0;
  424.   for (i = 0; i < 4; i++) {
  425.     if (!isxdigit(json[i])) {
  426.       *err = i+1;
  427.       return 0;
  428.     }
  429.     ucs = (ucs << 4) | hexdigit(json[i]);
  430.   }
  431.   *step = 4;
  432.  
  433.   if (end - json > 9 && // есть место
  434.       strncmp("\\u",json+4,2) == 0 && (ucs & 0xFC00) == 0xd800) {
  435.     int sp[2];
  436.     sp[0] = ucs; sp[1] = 0;
  437.     for (i = 6; i < 10; i++) {
  438.       if (!isxdigit(json[i])) {
  439.     *err = i+1;
  440.     return 0;
  441.       }
  442.       sp[1] = (sp[1] << 4) | hexdigit(json[i]);
  443.     }
  444.     if (!(ucs = surpair_to_ucs (sp)))
  445.       *err = i;
  446.     *step = 10;
  447.   }
  448.   return ucs;
  449. }
  450.  
  451. #define JSTR_INCR 512
  452.  
  453. /*
  454.   Переводит utf-8 в формате JSON string
  455.     "\"\\\/\b\f\r\t\n\uHHHH"
  456.   json, макимальной длины jmxl
  457.   в nil terminated *utf без внешних кавычек.
  458.   в *utf выделено памяти не меньше *size
  459.   если при вызове *utf != 0, то она д.б. malloc и как минимум *size байт и
  460.   может быть realloc().
  461.   jmxl - max длина json (если раньше не найден 0)
  462.  
  463.   Возвращает количество UCS СИМВОЛОВ результата
  464.   (отрицательное - some error, например нет закрывающей кавычки)
  465.   в *ofs смещение байта в json за закрывающей кавычкой (или байта с ошибкой)
  466.   в *size количество байт, помещенных в *utf (включая nil)
  467.  */
  468. int
  469. utf8json_to_utf (const char *json, int *ofs, int jmxl, char **utf, int *size)
  470. {
  471.   if (!*utf || *size < 1)
  472.     *utf = (char *)malloc(*size = JSTR_INCR);
  473.  
  474.   const char *s = json, *end = json+jmxl;
  475.   if (end < json)
  476.     end = (typeof(end))~0L;
  477.   u_char c;
  478.  
  479.   while ((c = *json++) != '"')
  480.     if (!c || json >= end) {
  481.       *ofs = json-s;
  482.       **utf = 0;
  483.       *size = 1;
  484.       return -1;
  485.     }
  486.  
  487.   int k, // UCS символов в *utf
  488.     l;   // байт (с nil) в *utf
  489.   int ucs, step, err;
  490.   k = l = 0;
  491.  
  492.  
  493.   while (json < end && (ucs = utf8_to_ucs(json,&step,&err)) != '"') {
  494.     if (err || ucs < ' ') {
  495.       *ofs = json-s;
  496.       (*utf)[l] = 0;
  497.       *size = l+1;
  498.       return -(k + 1);
  499.     }
  500.     if (ucs != '\\') {
  501.       if (*size <= l + step)
  502.     *utf = (char *)realloc(*utf,*size = *size+JSTR_INCR);
  503.  
  504.       ucs_to_utf8(ucs,*utf+l);
  505.       l += step;
  506.       k++;
  507.       json += step;
  508.     } else {
  509.       ucs = utf8_to_ucs(++json,&step,&err);
  510.       if (err)
  511.     ucs = 0; // simulate wrong input
  512.       switch (ucs) {
  513.       case '\\':
  514.       case '/':
  515.       case '"':
  516.     break;
  517.       case 'b':
  518.     ucs = '\b';
  519.     break;
  520.       case 't':
  521.     ucs = '\t';
  522.     break;
  523.       case 'n':
  524.     ucs = '\n';
  525.     break;
  526.       case 'r':
  527.     ucs = '\r';
  528.     break;
  529.       case 'f':
  530.     ucs = '\f';
  531.     break;
  532.       case 'u':
  533.     ucs = getjhex(++json,end,&step,&err);
  534.     break;
  535.       default:
  536.     if (!err) // в err смещение за ошибку, поэтому if
  537.       err = 1;
  538.       }
  539.       int lu = ucs_len(ucs);
  540.       if (err || lu == 0) {
  541.     *ofs = json-s + err? err: 0;
  542.     (*utf)[l] = 0;
  543.     *size = l+1;
  544.     return -(k + 1);
  545.       }
  546.       if (*size <= l + lu)
  547.     *utf = (char *)realloc(*utf,*size = *size+JSTR_INCR);
  548.       l += ucs_to_utf8(ucs,*utf+l);
  549.       json += step;
  550.       k++;      
  551.     }
  552.   }
  553.  
  554.   (*utf)[l] = 0;
  555.   *size = l+1;
  556.   *ofs = json - s + 1;
  557.  
  558.   return json < end ? k : ((*ofs)--, -(k + 1));
  559. }
  560.  
  561. // возвращает длину в байтах (включая "")
  562. int
  563. utf8str_to_json (const char *utf, int n, char *json, int size, int *ofs)
  564. {
  565.   if (size < 3)
  566.     return 0;
  567.  
  568.   *json++ = '"';
  569.   *ofs = 0;
  570.   size -= 2;
  571.   int l = 1, i = 0, c;
  572.  
  573.   while (n? i < n: (c = utf[i]&0xff)) {
  574.     switch (c) {
  575.     case '\\':
  576.     case '/':
  577.     case '"':
  578.       break;
  579.     case '\b':
  580.       c = 'b';
  581.       break;
  582.     case '\r':
  583.       c = 'r';
  584.       break;
  585.     case '\n':
  586.       c = 'n';
  587.       break;
  588.     case '\f':
  589.       c = 'f';
  590.       break;
  591.     case '\t':
  592.       c = 't';
  593.       break;
  594.     default:
  595.       if (c < ' ') {
  596.     if (size < l+6)
  597.       goto OUT;
  598.     sprintf(json+l,"\\u%04x",c);
  599.     l += 6;
  600.     i++;
  601.       } else {
  602.     if (size <= l)
  603.       goto OUT;
  604.     json[l++] = c;
  605.     i++;
  606.       }  
  607.       continue;
  608.     }
  609.     if (size < l+2)
  610.       break;
  611.     json[l++] = '\\';
  612.     json[l++] = c;
  613.     i++;
  614.   }
  615.  OUT:;
  616.   json[l++] = '"';
  617.   json[l] = 0;
  618.   *ofs = i;
  619.   return l;
  620. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement