/src/kcodecs/src/probers/CharDistribution.h
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | SPDX-FileCopyrightText: 1998 Netscape Communications Corporation <developer@mozilla.org> |
3 | | |
4 | | SPDX-License-Identifier: MIT |
5 | | */ |
6 | | |
7 | | #ifndef CharDistribution_h__ |
8 | | #define CharDistribution_h__ |
9 | | |
10 | | #include "kcodecs_export.h" |
11 | | |
12 | 1.40k | #define ENOUGH_DATA_THRESHOLD 256 |
13 | | |
14 | | namespace kencodingprober |
15 | | { |
16 | | class KCODECS_NO_EXPORT CharDistributionAnalysis |
17 | | { |
18 | | public: |
19 | 7.43k | CharDistributionAnalysis() = default; |
20 | 7.43k | virtual ~CharDistributionAnalysis() = default; |
21 | | |
22 | | // Feed a character with known length |
23 | | void HandleOneChar(const char *aStr, unsigned int aCharLen) |
24 | 1.05M | { |
25 | | // we only care about 2-bytes character in our distribution analysis |
26 | 1.05M | const int code = (aCharLen == 2) ? GetCode(aStr) : -1; |
27 | | |
28 | 1.05M | if (code >= 0) { |
29 | 574k | mTotalChars++; |
30 | | // code is valid |
31 | 574k | if ((unsigned int)code < mTableSize) { |
32 | 416k | if (mCharToFreqOrder[code] < 512) { |
33 | 364k | mFreqChars++; |
34 | 364k | } |
35 | 416k | } |
36 | 574k | } |
37 | 1.05M | } |
38 | | |
39 | | // return confidence base on existing data |
40 | | float GetConfidence(); |
41 | | |
42 | | // It is not necessary to receive all data to draw conclusion. For charset detection, |
43 | | // certain amount of data is enough |
44 | | bool GotEnoughData() |
45 | 1.40k | { |
46 | 1.40k | return mTotalChars > ENOUGH_DATA_THRESHOLD; |
47 | 1.40k | } |
48 | | |
49 | | protected: |
50 | | // Characters are not handled based on its original encoded value, but |
51 | | // converted to an encoding specific unique code. |
52 | | // This allows multiple encoding formats (e.g. SJIS and EUCJP) of an |
53 | | // encoding (like JIS X 213) to share one frequency table, mapping this |
54 | | // code to its frequency. |
55 | | virtual int GetCode(const char * /* str */) = 0; |
56 | | |
57 | | // The number of characters whose frequency order is less than 512 |
58 | | unsigned int mFreqChars = 0; |
59 | | |
60 | | // Total character encountered. |
61 | | unsigned int mTotalChars = 0; |
62 | | |
63 | | // Mapping table to get frequency order from code (from GetCode()) |
64 | | const short *mCharToFreqOrder = nullptr; |
65 | | |
66 | | // Size of above table |
67 | | unsigned int mTableSize = 0; |
68 | | |
69 | | // This is a constant value varies from language to language, it is used in |
70 | | // calculating confidence. See my paper for further detail. |
71 | | float mTypicalDistributionRatio = 0.0f; |
72 | | }; |
73 | | |
74 | | class KCODECS_NO_EXPORT EUCKRDistributionAnalysis : public CharDistributionAnalysis |
75 | | { |
76 | | public: |
77 | | EUCKRDistributionAnalysis(); |
78 | | |
79 | | protected: |
80 | | // for euc-KR encoding, we are interested |
81 | | // first byte range: 0xb0 -- 0xfe |
82 | | // second byte range: 0xa1 -- 0xfe |
83 | | // no validation needed here. State machine has done that |
84 | | int GetCode(const char *str) override |
85 | 122k | { |
86 | 122k | if ((unsigned char)*str >= (unsigned char)0xb0) { |
87 | 42.0k | return 94 * ((unsigned char)str[0] - (unsigned char)0xb0) + (unsigned char)str[1] - (unsigned char)0xa1; |
88 | 80.3k | } else { |
89 | 80.3k | return -1; |
90 | 80.3k | } |
91 | 122k | } |
92 | | }; |
93 | | |
94 | | class KCODECS_NO_EXPORT GB2312DistributionAnalysis : public CharDistributionAnalysis |
95 | | { |
96 | | public: |
97 | | GB2312DistributionAnalysis(); |
98 | | |
99 | | protected: |
100 | | // for GB2312 encoding, we are interested |
101 | | // first byte range: 0xb0 -- 0xfe |
102 | | // second byte range: 0xa1 -- 0xfe |
103 | | // no validation needed here. State machine has done that |
104 | | int GetCode(const char *str) override |
105 | 308k | { |
106 | 308k | if ((unsigned char)*str >= (unsigned char)0xb0 && (unsigned char)str[1] >= (unsigned char)0xa1) { |
107 | 62.8k | return 94 * ((unsigned char)str[0] - (unsigned char)0xb0) + (unsigned char)str[1] - (unsigned char)0xa1; |
108 | 245k | } else { |
109 | 245k | return -1; |
110 | 245k | } |
111 | 308k | } |
112 | | }; |
113 | | |
114 | | class KCODECS_NO_EXPORT Big5DistributionAnalysis : public CharDistributionAnalysis |
115 | | { |
116 | | public: |
117 | | Big5DistributionAnalysis(); |
118 | | |
119 | | protected: |
120 | | // for big5 encoding, we are interested |
121 | | // first byte range: 0xa4 -- 0xfe |
122 | | // second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe |
123 | | // no validation needed here. State machine has done that |
124 | | int GetCode(const char *str) override |
125 | 272k | { |
126 | 272k | if ((unsigned char)*str >= (unsigned char)0xa4) |
127 | 271k | if ((unsigned char)str[1] >= (unsigned char)0xa1) { |
128 | 269k | return 157 * ((unsigned char)str[0] - (unsigned char)0xa4) + (unsigned char)str[1] - (unsigned char)0xa1 + 63; |
129 | 269k | } else { |
130 | 2.38k | return 157 * ((unsigned char)str[0] - (unsigned char)0xa4) + (unsigned char)str[1] - (unsigned char)0x40; |
131 | 2.38k | } |
132 | 514 | else { |
133 | 514 | return -1; |
134 | 514 | } |
135 | 272k | } |
136 | | }; |
137 | | |
138 | | class KCODECS_NO_EXPORT SJISDistributionAnalysis : public CharDistributionAnalysis |
139 | | { |
140 | | public: |
141 | | SJISDistributionAnalysis(); |
142 | | |
143 | | protected: |
144 | | // for sjis encoding, we are interested |
145 | | // first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe |
146 | | // second byte range: 0x40 -- 0x7e, 0x81 -- oxfe |
147 | | // no validation needed here. State machine has done that |
148 | | int GetCode(const char *str) override |
149 | 48.6k | { |
150 | 48.6k | int code; |
151 | 48.6k | if ((unsigned char)*str >= (unsigned char)0x81 && (unsigned char)*str <= (unsigned char)0x9f) { |
152 | 34.0k | code = 188 * ((unsigned char)str[0] - (unsigned char)0x81); |
153 | 34.0k | } else if ((unsigned char)*str >= (unsigned char)0xe0 && (unsigned char)*str <= (unsigned char)0xef) { |
154 | 14.2k | code = 188 * ((unsigned char)str[0] - (unsigned char)0xe0 + 31); |
155 | 14.2k | } else { |
156 | 396 | return -1; |
157 | 396 | } |
158 | 48.2k | code += (unsigned char)*(str + 1) - 0x40; |
159 | 48.2k | if ((unsigned char)str[1] > (unsigned char)0x7f) { |
160 | 43.7k | code--; |
161 | 43.7k | } |
162 | 48.2k | return code; |
163 | 48.6k | } |
164 | | }; |
165 | | |
166 | | class KCODECS_NO_EXPORT EUCJPDistributionAnalysis : public CharDistributionAnalysis |
167 | | { |
168 | | public: |
169 | | EUCJPDistributionAnalysis(); |
170 | | |
171 | | protected: |
172 | | // for euc-JP encoding, we are interested |
173 | | // first byte range: 0xa0 -- 0xfe |
174 | | // second byte range: 0xa1 -- 0xfe |
175 | | // no validation needed here. State machine has done that |
176 | | int GetCode(const char *str) override |
177 | 150k | { |
178 | 150k | if ((unsigned char)*str >= (unsigned char)0xa0) { |
179 | 149k | return 94 * ((unsigned char)str[0] - (unsigned char)0xa1) + (unsigned char)str[1] - (unsigned char)0xa1; |
180 | 149k | } else { |
181 | 393 | return -1; |
182 | 393 | } |
183 | 150k | } |
184 | | }; |
185 | | } |
186 | | #endif // CharDistribution_h__ |