Coverage Report

Created: 2026-07-30 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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__