Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "nscore.h"
7 :
8 : #include "nsUniversalDetector.h"
9 :
10 : #include "nsMBCSGroupProber.h"
11 : #include "nsEscCharsetProber.h"
12 : #include "nsLatin1Prober.h"
13 :
14 0 : nsUniversalDetector::nsUniversalDetector()
15 : {
16 0 : mDone = false;
17 0 : mBestGuess = -1; //illegal value as signal
18 0 : mInTag = false;
19 0 : mEscCharSetProber = nullptr;
20 :
21 0 : mStart = true;
22 0 : mDetectedCharset = nullptr;
23 0 : mGotData = false;
24 0 : mInputState = ePureAscii;
25 0 : mLastChar = '\0';
26 :
27 : uint32_t i;
28 0 : for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
29 0 : mCharSetProbers[i] = nullptr;
30 0 : }
31 :
32 0 : nsUniversalDetector::~nsUniversalDetector()
33 : {
34 0 : for (int32_t i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
35 0 : delete mCharSetProbers[i];
36 :
37 0 : delete mEscCharSetProber;
38 0 : }
39 :
40 : void
41 0 : nsUniversalDetector::Reset()
42 : {
43 0 : mDone = false;
44 0 : mBestGuess = -1; //illegal value as signal
45 0 : mInTag = false;
46 :
47 0 : mStart = true;
48 0 : mDetectedCharset = nullptr;
49 0 : mGotData = false;
50 0 : mInputState = ePureAscii;
51 0 : mLastChar = '\0';
52 :
53 0 : if (mEscCharSetProber)
54 0 : mEscCharSetProber->Reset();
55 :
56 : uint32_t i;
57 0 : for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
58 0 : if (mCharSetProbers[i])
59 0 : mCharSetProbers[i]->Reset();
60 0 : }
61 :
62 : //---------------------------------------------------------------------
63 : #define SHORTCUT_THRESHOLD (float)0.95
64 : #define MINIMUM_THRESHOLD (float)0.20
65 :
66 0 : nsresult nsUniversalDetector::HandleData(const char* aBuf, uint32_t aLen)
67 : {
68 0 : if(mDone)
69 0 : return NS_OK;
70 :
71 0 : if (aLen > 0)
72 0 : mGotData = true;
73 :
74 : //If the data starts with BOM, we know it is UTF
75 0 : if (mStart)
76 : {
77 0 : mStart = false;
78 0 : if (aLen >= 2) {
79 0 : switch (aBuf[0]) {
80 : case '\xEF':
81 0 : if ((aLen > 2) && ('\xBB' == aBuf[1]) && ('\xBF' == aBuf[2])) {
82 : // EF BB BF UTF-8 encoded BOM
83 0 : mDetectedCharset = "UTF-8";
84 : }
85 0 : break;
86 : case '\xFE':
87 0 : if ('\xFF' == aBuf[1]) {
88 : // FE FF UTF-16, big endian BOM
89 0 : mDetectedCharset = "UTF-16BE";
90 : }
91 0 : break;
92 : case '\xFF':
93 0 : if ('\xFE' == aBuf[1]) {
94 : // FF FE UTF-16, little endian BOM
95 0 : mDetectedCharset = "UTF-16LE";
96 : }
97 0 : break;
98 : } // switch
99 : }
100 :
101 0 : if (mDetectedCharset)
102 : {
103 0 : mDone = true;
104 0 : return NS_OK;
105 : }
106 : }
107 :
108 : uint32_t i;
109 0 : for (i = 0; i < aLen; i++)
110 : {
111 : //other than 0xa0, if every othe character is ascii, the page is ascii
112 0 : if (aBuf[i] & '\x80' && aBuf[i] != '\xA0') //Since many Ascii only page contains NBSP
113 : {
114 : //we got a non-ascii byte (high-byte)
115 0 : if (mInputState != eHighbyte)
116 : {
117 : //adjust state
118 0 : mInputState = eHighbyte;
119 :
120 : //kill mEscCharSetProber if it is active
121 0 : if (mEscCharSetProber) {
122 0 : delete mEscCharSetProber;
123 0 : mEscCharSetProber = nullptr;
124 : }
125 :
126 : //start multibyte and singlebyte charset prober
127 0 : if (nullptr == mCharSetProbers[0])
128 : {
129 0 : mCharSetProbers[0] = new nsMBCSGroupProber();
130 0 : if (nullptr == mCharSetProbers[0])
131 0 : return NS_ERROR_OUT_OF_MEMORY;
132 : }
133 0 : if (nullptr == mCharSetProbers[2])
134 : {
135 0 : mCharSetProbers[2] = new nsLatin1Prober;
136 0 : if (nullptr == mCharSetProbers[2])
137 0 : return NS_ERROR_OUT_OF_MEMORY;
138 : }
139 : }
140 : }
141 : else
142 : {
143 : //ok, just pure ascii so far
144 0 : if ((ePureAscii == mInputState) && (aBuf[i] == '\033'))
145 : {
146 : //found escape character
147 0 : mInputState = eEscAscii;
148 : }
149 0 : mLastChar = aBuf[i];
150 : }
151 : }
152 :
153 : nsProbingState st;
154 0 : switch (mInputState)
155 : {
156 : case eEscAscii:
157 0 : if (nullptr == mEscCharSetProber) {
158 0 : mEscCharSetProber = new nsEscCharSetProber();
159 0 : if (nullptr == mEscCharSetProber)
160 0 : return NS_ERROR_OUT_OF_MEMORY;
161 : }
162 0 : st = mEscCharSetProber->HandleData(aBuf, aLen);
163 0 : if (st == eFoundIt)
164 : {
165 0 : mDone = true;
166 0 : mDetectedCharset = mEscCharSetProber->GetCharSetName();
167 : }
168 0 : break;
169 : case eHighbyte:
170 0 : for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
171 : {
172 0 : if (mCharSetProbers[i])
173 : {
174 0 : st = mCharSetProbers[i]->HandleData(aBuf, aLen);
175 0 : if (st == eFoundIt)
176 : {
177 0 : mDone = true;
178 0 : mDetectedCharset = mCharSetProbers[i]->GetCharSetName();
179 0 : return NS_OK;
180 : }
181 : }
182 : }
183 0 : break;
184 :
185 : default: //pure ascii
186 : ;//do nothing here
187 : }
188 0 : return NS_OK;
189 : }
190 :
191 :
192 : //---------------------------------------------------------------------
193 0 : void nsUniversalDetector::DataEnd()
194 : {
195 0 : if (!mGotData)
196 : {
197 : // we haven't got any data yet, return immediately
198 : // caller program sometimes call DataEnd before anything has been sent to detector
199 0 : return;
200 : }
201 :
202 0 : if (mDetectedCharset)
203 : {
204 0 : mDone = true;
205 0 : Report(mDetectedCharset);
206 0 : return;
207 : }
208 :
209 0 : switch (mInputState)
210 : {
211 : case eHighbyte:
212 : {
213 : float proberConfidence;
214 0 : float maxProberConfidence = (float)0.0;
215 0 : int32_t maxProber = 0;
216 :
217 0 : for (int32_t i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
218 : {
219 0 : if (mCharSetProbers[i])
220 : {
221 0 : proberConfidence = mCharSetProbers[i]->GetConfidence();
222 0 : if (proberConfidence > maxProberConfidence)
223 : {
224 0 : maxProberConfidence = proberConfidence;
225 0 : maxProber = i;
226 : }
227 : }
228 : }
229 : //do not report anything because we are not confident of it, that's in fact a negative answer
230 0 : if (maxProberConfidence > MINIMUM_THRESHOLD)
231 0 : Report(mCharSetProbers[maxProber]->GetCharSetName());
232 : }
233 0 : break;
234 : case eEscAscii:
235 0 : break;
236 : default:
237 : ;
238 : }
239 0 : return;
240 : }
|