Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_QRDecodedBitStreamParser.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "barcode.h"\r
8 #include "include/BC_QRCoderMode.h"\r
9 #include "include/BC_CommonBitSource.h"\r
10 #include "include/BC_CommonECI.h"\r
11 #include "include/BC_QRDecodedBitStreamParser.h"\r
12 #include "include/BC_CommonCharacterSetECI.h"\r
13 #include "include/BC_CommonDecoderResult.h"\r
14 #include "include/BC_UtilCodingConvert.h"\r
15 FX_LPCSTR CBC_QRDecodedBitStreamParser::UTF_8 = "utf8";\r
16 const FX_CHAR CBC_QRDecodedBitStreamParser::ALPHANUMERIC_CHARS[45] = {\r
17     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',\r
18     'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',\r
19     'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',\r
20     ' ', '$', '%', '*', '+', '-', '.', '/', ':'\r
21 };\r
22 CBC_QRDecodedBitStreamParser::CBC_QRDecodedBitStreamParser()\r
23 {\r
24 }\r
25 CBC_QRDecodedBitStreamParser::~CBC_QRDecodedBitStreamParser()\r
26 {\r
27 }\r
28 CBC_CommonDecoderResult* CBC_QRDecodedBitStreamParser::Decode(CFX_ByteArray *bytes, CBC_QRCoderVersion *version,\r
29         CBC_QRCoderErrorCorrectionLevel* ecLevel, FX_INT32 byteModeDecode, FX_INT32 &e)\r
30 {\r
31     CBC_CommonBitSource bits(bytes);\r
32     CFX_ByteString result;\r
33     CBC_CommonCharacterSetECI* currentCharacterSetECI = NULL;\r
34     FX_BOOL fc1Infact = FALSE;\r
35     CFX_Int32Array byteSegments;\r
36     CBC_QRCoderMode* mode = NULL;\r
37     do {\r
38         if(bits.Available() < 4) {\r
39             mode = CBC_QRCoderMode::sTERMINATOR;\r
40         } else {\r
41             FX_INT32 iTemp1 = bits.ReadBits(4, e);\r
42             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
43             mode = CBC_QRCoderMode::ForBits(iTemp1, e);\r
44             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
45             if(mode == NULL) {\r
46                 e = BCExceptionUnSupportMode;\r
47                 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
48             }\r
49         }\r
50         if(!(mode == CBC_QRCoderMode::sTERMINATOR)) {\r
51             if(mode == CBC_QRCoderMode::sFNC1_FIRST_POSITION || mode == CBC_QRCoderMode::sFNC1_SECOND_POSITION) {\r
52                 fc1Infact = TRUE;\r
53             } else if(mode == CBC_QRCoderMode::sSTRUCTURED_APPEND) {\r
54                 bits.ReadBits(16, e);\r
55                 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
56             } else if(mode == CBC_QRCoderMode::sECI) {\r
57                 FX_INT32 value = ParseECIValue(&bits, e);\r
58                 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
59                 currentCharacterSetECI = CBC_CommonCharacterSetECI::GetCharacterSetECIByValue(value);\r
60             } else {\r
61                 if(mode == CBC_QRCoderMode::sGBK) {\r
62                     bits.ReadBits(4, e);\r
63                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
64                 }\r
65                 FX_INT32 numBits = mode->GetCharacterCountBits(version, e);\r
66                 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
67                 FX_INT32 count = bits.ReadBits(numBits, e);\r
68                 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
69                 if(mode == CBC_QRCoderMode::sNUMERIC) {\r
70                     DecodeNumericSegment(&bits, result, count, e);\r
71                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
72                 } else if(mode == CBC_QRCoderMode::sALPHANUMERIC) {\r
73                     DecodeAlphanumericSegment(&bits, result, count, fc1Infact, e);\r
74                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
75                 } else if(mode == CBC_QRCoderMode::sBYTE) {\r
76                     DecodeByteSegment(&bits, result, count, currentCharacterSetECI, &byteSegments, byteModeDecode, e);\r
77                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
78                 } else if(mode == CBC_QRCoderMode::sGBK) {\r
79                     DecodeGBKSegment(&bits, result, count, e);\r
80                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
81                 } else if(mode == CBC_QRCoderMode::sKANJI) {\r
82                     DecodeKanjiSegment(&bits, result, count, e);\r
83                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
84                 } else {\r
85                     e = BCExceptionUnSupportMode;\r
86                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
87                 }\r
88             }\r
89         }\r
90     } while (!(mode == CBC_QRCoderMode::sTERMINATOR));\r
91     CBC_CommonDecoderResult *tempCd = FX_NEW CBC_CommonDecoderResult();\r
92     tempCd->Init(*bytes, result, byteSegments, ecLevel, e);\r
93     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
94     return tempCd;\r
95 }\r
96 void CBC_QRDecodedBitStreamParser::DecodeGBKSegment(CBC_CommonBitSource* bits, CFX_ByteString &result, FX_INT32 count, FX_INT32 &e)\r
97 {\r
98     CFX_ByteString buffer;\r
99     FX_INT32 offset = 0;\r
100     while (count > 0) {\r
101         FX_INT32 twoBytes = bits->ReadBits(13, e);\r
102         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
103         FX_INT32 assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);\r
104         if (assembledTwoBytes <= 0x0095d) {\r
105             assembledTwoBytes += 0x0a1a1;\r
106         } else {\r
107             assembledTwoBytes += 0x0a6a1;\r
108         }\r
109         buffer += (FX_BYTE) (assembledTwoBytes >> 8);\r
110         buffer += (FX_BYTE) assembledTwoBytes;\r
111         count--;\r
112     }\r
113     CBC_UtilCodingConvert::LocaleToUtf8(buffer, result);\r
114 }\r
115 void CBC_QRDecodedBitStreamParser::DecodeKanjiSegment(CBC_CommonBitSource* bits, CFX_ByteString &result, FX_INT32 count, FX_INT32 &e)\r
116 {\r
117     CFX_ByteString buffer;\r
118     while (count > 0) {\r
119         FX_INT32 twoBytes = bits->ReadBits(13, e);\r
120         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
121         FX_INT32 assembledTwoBytes = ((twoBytes / 0x0c0) << 8) | (twoBytes % 0x0c0);\r
122         if (assembledTwoBytes <= 0x01f00) {\r
123             assembledTwoBytes += 0x08140;\r
124         } else {\r
125             assembledTwoBytes += 0x0c140;\r
126         }\r
127         buffer += (FX_BYTE) (assembledTwoBytes >> 8);\r
128         buffer += (FX_BYTE) assembledTwoBytes;\r
129         count--;\r
130     }\r
131     CBC_UtilCodingConvert::LocaleToUtf8(buffer, result);\r
132 }\r
133 void CBC_QRDecodedBitStreamParser::DecodeByteSegment(CBC_CommonBitSource* bits, CFX_ByteString &result, FX_INT32 count,\r
134         CBC_CommonCharacterSetECI *currentCharacterSetECI,\r
135         CFX_Int32Array *byteSegments, FX_INT32 byteModeDecode, FX_INT32 &e)\r
136 {\r
137     if(count < 0) {\r
138         e = BCExceptionNotFound;\r
139         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
140     }\r
141     if((count << 3) > bits->Available()) {\r
142         e = BCExceptionRead;\r
143         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
144     }\r
145     FX_BYTE *readBytes = FX_Alloc(FX_BYTE, count);\r
146     FXSYS_memset32(readBytes, 0x00, count);\r
147     for(FX_INT32 i = 0; i < count; i++) {\r
148         readBytes[i] = (FX_BYTE) bits->ReadBits(8, e);\r
149         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
150     }\r
151     CFX_ByteString bs(readBytes, count);\r
152     result += bs;\r
153     FX_Free(readBytes);\r
154 }\r
155 void CBC_QRDecodedBitStreamParser::DecodeAlphanumericSegment(CBC_CommonBitSource* bits,\r
156         CFX_ByteString &result, FX_INT32 count, FX_BOOL fac1InEffect, FX_INT32 &e)\r
157 {\r
158     FX_INT32 start = result.GetLength();\r
159     while(count > 1) {\r
160         FX_INT32 nextTwoCharsBits = bits->ReadBits(11, e);\r
161         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
162         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[nextTwoCharsBits / 45]);\r
163         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[nextTwoCharsBits % 45]);\r
164         count -= 2;\r
165     }\r
166     if(count == 1) {\r
167         FX_INT32 itemp = bits->ReadBits(6, e);\r
168         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
169         BC_FX_ByteString_Append(result,  1, ALPHANUMERIC_CHARS[itemp]);\r
170     }\r
171     if(fac1InEffect) {\r
172         for(FX_INT32 i = start; i < result.GetLength(); i++) {\r
173             if(result[i] == '%') {\r
174                 if((i < result.GetLength() - 1) && result[i + 1] == '%') {\r
175                     result.Delete(i + 1, 1);\r
176                 } else {\r
177                     result.SetAt(i, (FX_CHAR)0x1d);\r
178                 }\r
179             }\r
180         }\r
181     }\r
182 }\r
183 void CBC_QRDecodedBitStreamParser::DecodeNumericSegment(CBC_CommonBitSource* bits, CFX_ByteString &result, FX_INT32 count, FX_INT32 &e)\r
184 {\r
185     while(count >= 3) {\r
186         FX_INT32 threeDigitsBits = bits->ReadBits(10, e);\r
187         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
188         if(threeDigitsBits >= 1000) {\r
189             e = BCExceptionRead;\r
190             BC_EXCEPTION_CHECK_ReturnVoid(e);\r
191         }\r
192         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[threeDigitsBits / 100]);\r
193         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]);\r
194         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[threeDigitsBits % 10]);\r
195         count -= 3;\r
196     }\r
197     if(count == 2) {\r
198         FX_INT32 twoDigitBits = bits->ReadBits(7, e);\r
199         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
200         if(twoDigitBits >= 100) {\r
201             e = BCExceptionRead;\r
202             BC_EXCEPTION_CHECK_ReturnVoid(e);\r
203         }\r
204         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[twoDigitBits / 10]);\r
205         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[twoDigitBits % 10]);\r
206     } else if(count == 1) {\r
207         FX_INT32 digitBits = bits->ReadBits(4, e);\r
208         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
209         if(digitBits >= 10) {\r
210             e = BCExceptionRead;\r
211             BC_EXCEPTION_CHECK_ReturnVoid(e);\r
212         }\r
213         BC_FX_ByteString_Append(result, 1, ALPHANUMERIC_CHARS[digitBits]);\r
214     }\r
215 }\r
216 const CFX_ByteString CBC_QRDecodedBitStreamParser::GuessEncoding(CFX_ByteArray *bytes)\r
217 {\r
218     return *UTF_8;\r
219 }\r
220 FX_INT32 CBC_QRDecodedBitStreamParser::ParseECIValue(CBC_CommonBitSource* bits, FX_INT32 &e)\r
221 {\r
222     FX_INT32 firstByte = bits->ReadBits(8, e);\r
223     BC_EXCEPTION_CHECK_ReturnValue(e, 0);\r
224     if((firstByte & 0x80) == 0) {\r
225         return firstByte & 0x7f;\r
226     } else if((firstByte & 0xc0) == 0x80) {\r
227         FX_INT32 secondByte = bits->ReadBits(8, e);\r
228         BC_EXCEPTION_CHECK_ReturnValue(e, 0);\r
229         return ((firstByte & 0x3f) << 8) | secondByte;\r
230     } else if((firstByte & 0xe0) == 0xc0) {\r
231         FX_INT32 secondThirdByte = bits->ReadBits(16, e);\r
232         BC_EXCEPTION_CHECK_ReturnValue(e, 0);\r
233         return ((firstByte & 0x1f) << 16) | secondThirdByte;\r
234     }\r
235     e = BCExceptionBadECI;\r
236     BC_EXCEPTION_CHECK_ReturnValue(e, 0);\r
237     return 0;\r
238 }\r