Preserve query in geo URI
[zxing.git] / csharp / qrcode / decoder / BitMatrixParser.cs
1 /*\r
2 * Copyright 2007 ZXing authors\r
3 *\r
4 * Licensed under the Apache License, Version 2.0 (the "License");\r
5 * you may not use this file except in compliance with the License.\r
6 * You may obtain a copy of the License at\r
7 *\r
8 *      http://www.apache.org/licenses/LICENSE-2.0\r
9 *\r
10 * Unless required by applicable law or agreed to in writing, software\r
11 * distributed under the License is distributed on an "AS IS" BASIS,\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13 * See the License for the specific language governing permissions and\r
14 * limitations under the License.\r
15 */\r
16 using System;\r
17 using ReaderException = com.google.zxing.ReaderException;\r
18 using BitMatrix = com.google.zxing.common.BitMatrix;\r
19 namespace com.google.zxing.qrcode.decoder\r
20 {\r
21         \r
22         /// <author>  Sean Owen\r
23         /// </author>\r
24         /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
25         /// </author>\r
26         sealed class BitMatrixParser\r
27         {\r
28                 \r
29                 //UPGRADE_NOTE: Final was removed from the declaration of 'bitMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
30                 private BitMatrix bitMatrix;\r
31                 private Version parsedVersion;\r
32                 private FormatInformation parsedFormatInfo;\r
33                 \r
34                 /// <param name="bitMatrix">{@link BitMatrix} to parse\r
35                 /// </param>\r
36                 /// <throws>  ReaderException if dimension is not >= 21 and 1 mod 4 </throws>\r
37                 internal BitMatrixParser(BitMatrix bitMatrix)\r
38                 {\r
39                         int dimension = bitMatrix.Dimension;\r
40                         if (dimension < 21 || (dimension & 0x03) != 1)\r
41                         {\r
42                                 throw ReaderException.Instance;\r
43                         }\r
44                         this.bitMatrix = bitMatrix;\r
45                 }\r
46                 \r
47                 /// <summary> <p>Reads format information from one of its two locations within the QR Code.</p>\r
48                 /// \r
49                 /// </summary>\r
50                 /// <returns> {@link FormatInformation} encapsulating the QR Code's format info\r
51                 /// </returns>\r
52                 /// <throws>  ReaderException if both format information locations cannot be parsed as </throws>\r
53                 /// <summary> the valid encoding of format information\r
54                 /// </summary>\r
55                 internal FormatInformation readFormatInformation()\r
56                 {\r
57                         \r
58                         if (parsedFormatInfo != null)\r
59                         {\r
60                                 return parsedFormatInfo;\r
61                         }\r
62                         \r
63                         // Read top-left format info bits\r
64                         int formatInfoBits = 0;\r
65                         for (int i = 0; i < 6; i++)\r
66                         {\r
67                                 formatInfoBits = copyBit(i, 8, formatInfoBits);\r
68                         }\r
69                         // .. and skip a bit in the timing pattern ...\r
70                         formatInfoBits = copyBit(7, 8, formatInfoBits);\r
71                         formatInfoBits = copyBit(8, 8, formatInfoBits);\r
72                         formatInfoBits = copyBit(8, 7, formatInfoBits);\r
73                         // .. and skip a bit in the timing pattern ...\r
74                         for (int j = 5; j >= 0; j--)\r
75                         {\r
76                                 formatInfoBits = copyBit(8, j, formatInfoBits);\r
77                         }\r
78                         \r
79                         parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);\r
80                         if (parsedFormatInfo != null)\r
81                         {\r
82                                 return parsedFormatInfo;\r
83                         }\r
84                         \r
85                         // Hmm, failed. Try the top-right/bottom-left pattern\r
86                         int dimension = bitMatrix.Dimension;\r
87                         formatInfoBits = 0;\r
88                         int iMin = dimension - 8;\r
89                         for (int i = dimension - 1; i >= iMin; i--)\r
90                         {\r
91                                 formatInfoBits = copyBit(i, 8, formatInfoBits);\r
92                         }\r
93                         for (int j = dimension - 7; j < dimension; j++)\r
94                         {\r
95                                 formatInfoBits = copyBit(8, j, formatInfoBits);\r
96                         }\r
97                         \r
98                         parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);\r
99                         if (parsedFormatInfo != null)\r
100                         {\r
101                                 return parsedFormatInfo;\r
102                         }\r
103                         throw ReaderException.Instance;\r
104                 }\r
105                 \r
106                 /// <summary> <p>Reads version information from one of its two locations within the QR Code.</p>\r
107                 /// \r
108                 /// </summary>\r
109                 /// <returns> {@link Version} encapsulating the QR Code's version\r
110                 /// </returns>\r
111                 /// <throws>  ReaderException if both version information locations cannot be parsed as </throws>\r
112                 /// <summary> the valid encoding of version information\r
113                 /// </summary>\r
114                 internal Version readVersion()\r
115                 {\r
116                         \r
117                         if (parsedVersion != null)\r
118                         {\r
119                                 return parsedVersion;\r
120                         }\r
121                         \r
122                         int dimension = bitMatrix.Dimension;\r
123                         \r
124                         int provisionalVersion = (dimension - 17) >> 2;\r
125                         if (provisionalVersion <= 6)\r
126                         {\r
127                                 return Version.getVersionForNumber(provisionalVersion);\r
128                         }\r
129                         \r
130                         // Read top-right version info: 3 wide by 6 tall\r
131                         int versionBits = 0;\r
132                         int ijMin = dimension - 11;\r
133                         for (int j = 5; j >= 0; j--)\r
134                         {\r
135                                 for (int i = dimension - 9; i >= ijMin; i--)\r
136                                 {\r
137                                         versionBits = copyBit(i, j, versionBits);\r
138                                 }\r
139                         }\r
140                         \r
141                         parsedVersion = Version.decodeVersionInformation(versionBits);\r
142                         if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)\r
143                         {\r
144                                 return parsedVersion;\r
145                         }\r
146                         \r
147                         // Hmm, failed. Try bottom left: 6 wide by 3 tall\r
148                         versionBits = 0;\r
149                         for (int i = 5; i >= 0; i--)\r
150                         {\r
151                                 for (int j = dimension - 9; j >= ijMin; j--)\r
152                                 {\r
153                                         versionBits = copyBit(i, j, versionBits);\r
154                                 }\r
155                         }\r
156                         \r
157                         parsedVersion = Version.decodeVersionInformation(versionBits);\r
158                         if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension)\r
159                         {\r
160                                 return parsedVersion;\r
161                         }\r
162                         throw ReaderException.Instance;\r
163                 }\r
164                 \r
165                 private int copyBit(int i, int j, int versionBits)\r
166                 {\r
167                         return bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1;\r
168                 }\r
169                 \r
170                 /// <summary> <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the\r
171                 /// correct order in order to reconstitute the codewords bytes contained within the\r
172                 /// QR Code.</p>\r
173                 /// \r
174                 /// </summary>\r
175                 /// <returns> bytes encoded within the QR Code\r
176                 /// </returns>\r
177                 /// <throws>  ReaderException if the exact number of bytes expected is not read </throws>\r
178                 internal sbyte[] readCodewords()\r
179                 {\r
180                         \r
181                         FormatInformation formatInfo = readFormatInformation();\r
182                         Version version = readVersion();\r
183                         \r
184                         // Get the data mask for the format used in this QR Code. This will exclude\r
185                         // some bits from reading as we wind through the bit matrix.\r
186                         DataMask dataMask = DataMask.forReference((int) formatInfo.DataMask);\r
187                         int dimension = bitMatrix.Dimension;\r
188                         dataMask.unmaskBitMatrix(bitMatrix, dimension);\r
189                         \r
190                         BitMatrix functionPattern = version.buildFunctionPattern();\r
191                         \r
192                         bool readingUp = true;\r
193                         sbyte[] result = new sbyte[version.TotalCodewords];\r
194                         int resultOffset = 0;\r
195                         int currentByte = 0;\r
196                         int bitsRead = 0;\r
197                         // Read columns in pairs, from right to left\r
198                         for (int j = dimension - 1; j > 0; j -= 2)\r
199                         {\r
200                                 if (j == 6)\r
201                                 {\r
202                                         // Skip whole column with vertical alignment pattern;\r
203                                         // saves time and makes the other code proceed more cleanly\r
204                                         j--;\r
205                                 }\r
206                                 // Read alternatingly from bottom to top then top to bottom\r
207                                 for (int count = 0; count < dimension; count++)\r
208                                 {\r
209                                         int i = readingUp?dimension - 1 - count:count;\r
210                                         for (int col = 0; col < 2; col++)\r
211                                         {\r
212                                                 // Ignore bits covered by the function pattern\r
213                                                 if (!functionPattern.get_Renamed(j - col, i))\r
214                                                 {\r
215                                                         // Read a bit\r
216                                                         bitsRead++;\r
217                                                         currentByte <<= 1;\r
218                                                         if (bitMatrix.get_Renamed(j - col, i))\r
219                                                         {\r
220                                                                 currentByte |= 1;\r
221                                                         }\r
222                                                         // If we've made a whole byte, save it off\r
223                                                         if (bitsRead == 8)\r
224                                                         {\r
225                                                                 result[resultOffset++] = (sbyte) currentByte;\r
226                                                                 bitsRead = 0;\r
227                                                                 currentByte = 0;\r
228                                                         }\r
229                                                 }\r
230                                         }\r
231                                 }\r
232                                 readingUp ^= true; // readingUp = !readingUp; // switch directions\r
233                         }\r
234                         if (resultOffset != version.TotalCodewords)\r
235                         {\r
236                                 throw ReaderException.Instance;\r
237                         }\r
238                         return result;\r
239                 }\r
240         }\r
241 }