Проблемы с кодировкой и как можно их решить

Дата публикации 7 сен 2024 | Редактировалось 9 сен 2024
Код (Text):
  1. // unicode.c
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdint.h>
  6. #include <stdlib.h>
  7. #include <io.h>
  8. #include "unicode.h"
  9.  
  10. int isUTF8(const char *data, size_t size)
  11. {
  12.     const uint8_t *str = (uint8_t*)data;
  13.     const uint8_t *end = str + size;
  14.     uint8_t byte;
  15.     uint32_t code_length, i;
  16.     uint32_t ch;
  17.     while (str != end) {
  18.         byte = *str;
  19.         if (byte <= 0x7F) {
  20.             /* 1 byte sequence: U+0000..U+007F */
  21.             str += 1;
  22.             continue;
  23.         }
  24.  
  25.         if (0xC2 <= byte && byte <= 0xDF)
  26.             /* 0b110xxxxx: 2 bytes sequence */
  27.             code_length = 2;
  28.         else if (0xE0 <= byte && byte <= 0xEF)
  29.             /* 0b1110xxxx: 3 bytes sequence */
  30.             code_length = 3;
  31.         else if (0xF0 <= byte && byte <= 0xF4)
  32.             /* 0b11110xxx: 4 bytes sequence */
  33.             code_length = 4;
  34.         else {
  35.             /* invalid first byte of a multibyte character */
  36.             return 0;
  37.         }
  38.  
  39.         if (str + (code_length - 1) >= end) {
  40.             /* truncated string or invalid byte sequence */
  41.             return 0;
  42.         }
  43.  
  44.         /* Check continuation bytes: bit 7 should be set, bit 6 should be
  45.          * unset (b10xxxxxx). */
  46.         for (i=1; i < code_length; i++) {
  47.             if ((str[i] & 0xC0) != 0x80)
  48.                 return 0;
  49.         }
  50.  
  51.         if (code_length == 2) {
  52.             /* 2 bytes sequence: U+0080..U+07FF */
  53.             ch = ((str[0] & 0x1f) << 6) + (str[1] & 0x3f);
  54.             /* str[0] >= 0xC2, so ch >= 0x0080.
  55.                str[0] <= 0xDF, (str[1] & 0x3f) <= 0x3f, so ch <= 0x07ff */
  56.         } else if (code_length == 3) {
  57.             /* 3 bytes sequence: U+0800..U+FFFF */
  58.             ch = ((str[0] & 0x0f) << 12) + ((str[1] & 0x3f) << 6) +
  59.                   (str[2] & 0x3f);
  60.             /* (0xff & 0x0f) << 12 | (0xff & 0x3f) << 6 | (0xff & 0x3f) = 0xffff,
  61.                so ch <= 0xffff */
  62.             if (ch < 0x0800)
  63.                 return 0;
  64.  
  65.             /* surrogates (U+D800-U+DFFF) are invalid in UTF-8:
  66.                test if (0xD800 <= ch && ch <= 0xDFFF) */
  67.             if ((ch >> 11) == 0x1b)
  68.                 return 0;
  69.         } else if (code_length == 4) {
  70.             /* 4 bytes sequence: U+10000..U+10FFFF */
  71.             ch = ((str[0] & 0x07) << 18) + ((str[1] & 0x3f) << 12) +
  72.                  ((str[2] & 0x3f) << 6) + (str[3] & 0x3f);
  73.             if ((ch < 0x10000) || (0x10FFFF < ch))
  74.                 return 0;
  75.         }
  76.         str += code_length;
  77.     }
  78.     return 1;
  79. }
  80.  
  81. uint32_t Utf32Get(int bigEndian, const char *src)
  82. {
  83.     uint32_t codePoint;
  84.  
  85.     if (bigEndian)
  86.     {
  87.         codePoint = ((uint8_t)src[0] << 24) | ((uint8_t)src[1] << 16)
  88.             | ((uint8_t)src[2] << 8) | (uint8_t)src[3];
  89.     }
  90.     else
  91.     {
  92.         codePoint = ((uint8_t)src[3] << 24) | ((uint8_t)src[2] << 16)
  93.             | ((uint8_t)src[1] << 8) | (uint8_t)src[0];
  94.     }
  95.  
  96.     return codePoint;
  97.  
  98. }
  99.  
  100. int Utf8Put(int32_t codePoint, char *dst, size_t *numUnits)
  101. {
  102.  
  103.     if (numUnits != NULL)
  104.         *numUnits = 0;
  105.  
  106.     if ((codePoint < 0) || (0x10FFFF < codePoint))
  107.         return -1;
  108.  
  109.     if (dst == NULL)
  110.         return -1;
  111.  
  112.     // One-octet code point (Unicode range U+000000 to U+00007F)?
  113.     if (codePoint < 0x80)
  114.     {
  115.         dst[0] = codePoint & 0x7F;
  116.         if (numUnits != NULL)
  117.             *numUnits = 1;
  118.     }
  119.  
  120.     // Two-octet code point (Unicode range U+000080 to U+0007FF)?
  121.     else if (codePoint < 0x800)
  122.     {
  123.         dst[0] = 0xC0 | ((codePoint & 0x07C0) >> 6);
  124.         dst[1] = 0x80 | (codePoint & 0x003F);
  125.         if (numUnits != NULL)
  126.             *numUnits = 2;
  127.     }
  128.  
  129.     // Three-octet code point (Unicode range U+000800 to U+00FFFF)?
  130.     else if (codePoint < 0x10000)
  131.     {
  132.         dst[0] = 0xE0 | ((codePoint & 0x0F000) >> 12);
  133.         dst[1] = 0x80 | ((codePoint & 0x00FC0) >> 6);
  134.         dst[2] = 0x80 | (codePoint & 0x0003F);
  135.         if (numUnits != NULL)
  136.             *numUnits = 3;
  137.     }
  138.  
  139.     // Four-octet code point (Unicode range U+010000 to U+10FFFF)?
  140.     else
  141.     {
  142.         dst[0] = 0xF0 | ((codePoint & 0x1C0000) >> 18);
  143.         dst[1] = 0x80 | ((codePoint & 0x03F000) >> 12);
  144.         dst[2] = 0x80 | ((codePoint & 0x000FC0) >> 6);
  145.         dst[3] = 0x80 | (codePoint & 0x00003F);
  146.         if (numUnits != NULL)
  147.             *numUnits = 4;
  148.     }
  149.  
  150.     return 0;
  151. }
  152.  
  153. int Utf32Bom(const char *src)
  154. {
  155.     if (((uint8_t)src[0] == 0) && ((uint8_t)src[1] == 0)
  156.         && ((uint8_t)src[2] == 0xFE) && ((uint8_t)src[3] == 0xFF))
  157.     {
  158.         return 1;    // BOM, big-endian
  159.     }
  160.     else if (((uint8_t)src[0] == 0xFF) && ((uint8_t)src[1] == 0xFE)
  161.         && ((uint8_t)src[2] == 0) && ((uint8_t)src[3] == 0))
  162.     {
  163.         return -1;    // BOM, little-endian
  164.     }
  165.  
  166.     return 0;    // No BOM
  167.  
  168. }
  169.  
  170. size_t Utf32Utf8(const char *src, int srclen, int bom, char *dst, int dstlen)
  171. {
  172.     int bigEndian = 0;
  173.     int32_t codePoint;
  174.     size_t length, numUnits;
  175.  
  176.     length = 0;
  177.  
  178.     // Determine the byte order of the UTF-32 source string.
  179.     if(bom == UTF32BENB){ // UTF-32BE NoBOM
  180.         bigEndian = 1;
  181.     }
  182.     if(bom == UTF32LENB){ // UTF-32LE NoBOM
  183.         bigEndian = 0;
  184.     }
  185.  
  186.     if(bom != UTF32LENB && bom != UTF32BENB){
  187.         // if the bom has not been supplied
  188.         bigEndian = (Utf32Bom(src) >= 0);
  189.         if (bigEndian)
  190.         {
  191.             src += sizeof(uint32_t);
  192.             srclen -= sizeof(uint32_t);
  193.         }
  194.     }
  195.     // Encode the UTF-32 code points as UTF-8.
  196.     while (srclen > 0)
  197.     {
  198.         codePoint = Utf32Get(bigEndian, src);
  199.         if (codePoint < 0)
  200.         {
  201.             return -1;
  202.         }
  203.         src += sizeof(uint32_t);
  204.         srclen -= sizeof(uint32_t);
  205.         if ((dstlen < 4) && ((codePoint > 0x0FFFF) || ((dstlen < 3)
  206.                     && ((codePoint > 0x00800) || ((dstlen < 2)
  207.                     && ((codePoint > 0x0007F) || (dstlen < 1)))))))
  208.         {
  209.             return -1;
  210.         }
  211.         if (Utf8Put(codePoint, dst, &numUnits))
  212.         {
  213.             return -1;
  214.         }
  215.         dst += numUnits;
  216.         dstlen -= numUnits;
  217.         length += numUnits;
  218.     }
  219.  
  220.     if (dstlen >= 1)
  221.         *dst = '\0';
  222.  
  223.     return length;
  224.  
  225. }
  226.  
  227. int IsAnsi(const char *src, int len)
  228. {
  229.     int ret = 0;
  230.     char c;
  231.     while (--len)
  232.     {
  233.         c = *src;
  234.         // in ANSI range
  235.         if (c > 0x19 && c < 0x7F || c == 0x0A || c == 0x0D || c == 0x9){
  236.             ret = 1;
  237.             src++;
  238.         }
  239.         else{
  240.             ret = 0;
  241.             break;    // not in range of ANSI chars
  242.         }
  243.     }
  244.     return ret;
  245. }
  246.  
  247. int IsAscii(const char *data, size_t size)
  248. {
  249.     const uint8_t *str = (const uint8_t *)data;
  250.     const uint8_t *end = str + size;
  251.     for (; str != end; str++)
  252.     {
  253.         if (*str >= 0x80)
  254.             return 0;
  255.     }
  256.     return 1;
  257. }
  258.  
  259. void CheckUtf16LE(const wchar_t * wstr, int * cntLE, int * cntHigh)
  260. {
  261.     while(*wstr){
  262.  
  263.         if(*wstr == 0x000D)
  264.             (*cntLE)++;
  265.  
  266.         if((char)*wstr > (char)((*wstr)>>8))
  267.             (*cntHigh)++;
  268.  
  269.         wstr++;
  270.  
  271.     }
  272. }
  273.  
  274. void CheckUtf32LE(const uint32_t * wstr, int * cntLE, int * cntHigh)
  275. {
  276.     while(*wstr){
  277.  
  278.         if(*wstr == 0x0000000D)
  279.             (*cntLE)++;
  280.  
  281.         if((wchar_t)*wstr > (wchar_t)((*wstr)>>16))
  282.             (*cntHigh)++;
  283.  
  284.         wstr++;
  285.  
  286.     }
  287. }
  288.  
  289. void CheckUtf16BE(const wchar_t * wstr, int * cntBE, int * cntHigh)
  290. {
  291.     while(*wstr){
  292.  
  293.         if(*wstr == 0x0D00)
  294.             (*cntBE)++;
  295.  
  296.         if((char)((*wstr)>>8) > (char)*wstr)
  297.             (*cntHigh)++;
  298.  
  299.         wstr++;
  300.  
  301.     }
  302.  
  303. }
  304.  
  305. void CheckUtf32BE(const uint32_t * wstr, int * cntBE, int * cntHigh)
  306. {
  307.     while(*wstr){
  308.  
  309.         if(*wstr == 0x0D000000)
  310.             (*cntBE)++;
  311.  
  312.         if((wchar_t)((*wstr)>>16) > (wchar_t)*wstr)
  313.             (*cntHigh)++;
  314.  
  315.         wstr++;
  316.  
  317.     }
  318.  
  319. }
  320.  
  321. int AdjustUnix(char * src, int len)
  322. {
  323.     int cnt = 0;
  324.     char tmp[len*2];
  325.     char * ptmp = tmp, * psrc = src;
  326.  
  327.     // copy src to tmp while inserting CR before LF
  328.     while(*psrc)
  329.     {
  330.         if(*psrc == 0x0A){
  331.             *ptmp++ = 0x0D;
  332.             cnt++;
  333.         }
  334.         *ptmp++ = *psrc++;
  335.     }
  336.     // copy back to src
  337.     memcpy(src, tmp, len + cnt);
  338.     return len + cnt;
  339. }
  340.  
  341. int CheckUnix(const char * str)
  342. {
  343.     int i = 0;
  344.     char c;
  345.     while(*str)
  346.     {
  347.         c = *str++;
  348.         if(*str == 0x0A)
  349.         {
  350.             i++;
  351.             if(c == 0x0D)
  352.                 i--;
  353.         }
  354.     }
  355.     return i;
  356. }
  357.  
  358. int IsvalidUtf8(const char *str, int len, int *oneseq, int *twoseq, int *threeseq, int *fourseq, int *err)
  359. {
  360.     uint8_t c, c1, c2;
  361.  
  362.     while(*str)
  363.     {
  364.         c = *str++;
  365.  
  366.         //*********************************************************
  367.         // check for one byte ascii
  368.         //*********************************************************
  369.         //    1    7F
  370.         if(c <= 0x7F){
  371.             (*oneseq)++;
  372.             continue;
  373.         }
  374.  
  375.         //*********************************************************
  376.         // check for two byte sequences
  377.         //*********************************************************
  378.         //    2    C2..DF     80..BF
  379.         if(c >= 0xC2 && c <= 0xDF){
  380.             c = *str++;
  381.             if((c >= 0x80 && c <= 0xBF)){
  382.                 (*twoseq)++;
  383.                 continue;
  384.             }
  385.         }
  386.  
  387.         //*********************************************************
  388.         // check for three byte sequences
  389.         //*********************************************************
  390.         //    3    E0         A0..BF      80..BF
  391.         if(c == 0xE0){
  392.             c = *str++; c1 = *str++;
  393.             if(c >= 0xA0 && c <= 0xBF && c1 >= 0x80 && c1 <= 0xBF){
  394.                 (*threeseq)++;
  395.                 continue;
  396.             }
  397.         }
  398.         //    3    E1..EC     80..BF      80..BF
  399.         if(c >= 0xE1 && c <= 0xEC){
  400.             c = *str++; c1 = *str++;
  401.             if(c >= 0x80 && c <= 0xBF && c1 >= 0x80 && c1 <= 0xBF){
  402.                 (*threeseq)++;
  403.                 continue;
  404.             }
  405.         }
  406.         //    3    ED         80..9F      80..BF
  407.         if(c == 0xED){
  408.             c = *str++; c1 = *str++;
  409.             if(c >= 0x80 && c <= 0x9F && c1 >= 0x80 && c1 <= 0xBF){
  410.                 (*threeseq)++;
  411.                 continue;
  412.             }
  413.         }
  414.         //    3    EE..EF     80..BF      80..BF
  415.         if(c >= 0xEE && c <= 0xEF)
  416.         {
  417.             c = *str++; c1 = *str++;
  418.             if(c >= 0x80 && c <= 0xBF && c1 >= 0x80 || c1 <= 0xBF){
  419.                 (*threeseq)++;
  420.                 continue;
  421.             }
  422.         }
  423.  
  424.         //*********************************************************
  425.         // check for four byte sequences
  426.         //*********************************************************
  427.         //    4    F0         90..BF      80..BF     80..BF
  428.         if(c == 0xF0){
  429.             c = *str++; c1 = *str++; c2 = *str++;
  430.             if(c >= 0x90 && c <= 0xBF && c1 >= 0x80 && c1 <= 0xBF && c2 >= 0x80 && c2 <= 0xBF){
  431.                 (*fourseq)++;
  432.                 continue;
  433.             }
  434.         }
  435.         //    4    F1..F3     80..BF      80..BF     80..BF
  436.         if(c >= 0xF1 && c <= 0xF3){
  437.             c = *str++; c1 = *str++; c2 = *str++;
  438.             if(c >= 0x80 && c <= 0xBF && c1 >= 0x80 && c1 <= 0xBF && c2 >= 0x80 && c2 <= 0xBF){
  439.                 (*fourseq)++;
  440.                 continue;
  441.             }
  442.         }
  443.         //    4    F4         80..8F      80..BF     80..BF
  444.         if(c >= 0xF4){
  445.             c = *str++; c1 = *str++; c2 = *str++;
  446.             if(c >= 0x80 && c <= 0x8F && c1 >= 0x80 && c1 <= 0xBF && c2 >= 0x80 && c2 <= 0xBF){
  447.                 (*fourseq)++;
  448.                 continue;
  449.             }
  450.         }
  451.     }
  452.     return 0;
  453. }
  454.  
  455. int CheckBom(const wchar_t *str)
  456. {
  457.     uint32_t uc = *(uint32_t*)str;
  458.     if(uc == 0x0000FEFF)
  459.         return UTF32LEB; // Unicode-32LE BOM
  460.  
  461.     if(uc == 0xFFFE0000)
  462.         return UTF32BEB; // Unicode-32LE BOM
  463.  
  464.     if (str[0] == 0xFEFF)
  465.         return UTF16LE;    // Unicode-16LE BOM
  466.  
  467.     else if (str[0] == 0xFFFE)
  468.         return UTF16BE;    // Unicode-16BE BOM
  469.  
  470.     else if (str[0] == 0xBBEF)
  471.     {
  472.         if ((uint8_t)str[1] == 0xBF)
  473.             return UTF8B; // Unicode-UTF8 BOM
  474.         else
  475.             return NOBOM; // Unknown - return NOBOM
  476.     }
  477.     return NOBOM;
  478. }
  479.  
  480. int CheckUtf8(FILE * f)
  481. {
  482.     //**************************************************************
  483.     // Special case in that a UTF8 file without BOM could be normal
  484.     // ascii for 20k then have a few lines of unicode so need to
  485.     // check the whole file.
  486.     //**************************************************************
  487.     long len;
  488.     int err = 0, oneseq = 0, twoseq = 0, threeseq = 0, fourseq = 0;
  489.     rewind(f);
  490.     len = _filelength(_fileno(f));
  491.  
  492.     len = (len > 1000000) ? 1000000 : len; // one meg is enough though.
  493.  
  494.     char * buffer = malloc(len+10);
  495.     fread(buffer, len, 1, f);    // file is closed in DisplayFileHead()
  496.  
  497.     //**************************************************************
  498.     // Add a few zero's so that the while loop in isvalid_utf8()
  499.     // can if necessary go pass the end of the text without crashing,
  500.     // before exiting the loop. The buffer is 10 bytes larger.
  501.     //**************************************************************
  502.     memset(&buffer[len], 0, 9);
  503.     IsvalidUtf8(buffer, len, &oneseq, &twoseq, &threeseq, &fourseq, &err);
  504.      free(buffer);
  505.  
  506.     // guessing here
  507.     if(len > 1000){
  508.         if(twoseq >= 8 || threeseq >= 8 || fourseq >= 8)
  509.             return 1;
  510.  
  511.     }else if(len > 100){
  512.         if(twoseq >= 4 || threeseq >= 4 || fourseq >= 4)
  513.             return 1;
  514.  
  515.     }else if(len > 10){
  516.         if(twoseq >= 2 || threeseq >= 2 || fourseq >= 2)
  517.             return 1;
  518.  
  519.     }else if(len > 2){
  520.         if(twoseq >= 1 || threeseq >= 1 || fourseq >= 1)
  521.             return 1;
  522.  
  523.     }
  524.     return 0;
  525. }

0 104
CaptainObvious

CaptainObvious
Member

Регистрация:
18 янв 2024
Публикаций:
1