Preserve query in geo URI
[zxing.git] / csharp / qrcode / decoder / DataBlock.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 namespace com.google.zxing.qrcode.decoder\r
18 {\r
19         \r
20         /// <summary> <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into\r
21         /// multiple blocks, each of which is a unit of data and error-correction codewords. Each\r
22         /// is represented by an instance of this class.</p>\r
23         /// \r
24         /// </summary>\r
25         /// <author>  Sean Owen\r
26         /// </author>\r
27         /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
28         /// </author>\r
29         sealed class DataBlock\r
30         {\r
31                 internal int NumDataCodewords\r
32                 {\r
33                         get\r
34                         {\r
35                                 return numDataCodewords;\r
36                         }\r
37                         \r
38                 }\r
39                 internal sbyte[] Codewords\r
40                 {\r
41                         get\r
42                         {\r
43                                 return codewords;\r
44                         }\r
45                         \r
46                 }\r
47                 \r
48                 //UPGRADE_NOTE: Final was removed from the declaration of 'numDataCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
49                 private int numDataCodewords;\r
50                 //UPGRADE_NOTE: Final was removed from the declaration of 'codewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
51                 private sbyte[] codewords;\r
52                 \r
53                 private DataBlock(int numDataCodewords, sbyte[] codewords)\r
54                 {\r
55                         this.numDataCodewords = numDataCodewords;\r
56                         this.codewords = codewords;\r
57                 }\r
58                 \r
59                 /// <summary> <p>When QR Codes use multiple data blocks, they are actually interleaved.\r
60                 /// That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This\r
61                 /// method will separate the data into original blocks.</p>\r
62                 /// \r
63                 /// </summary>\r
64                 /// <param name="rawCodewords">bytes as read directly from the QR Code\r
65                 /// </param>\r
66                 /// <param name="version">version of the QR Code\r
67                 /// </param>\r
68                 /// <param name="ecLevel">error-correction level of the QR Code\r
69                 /// </param>\r
70                 /// <returns> {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the\r
71                 /// QR Code\r
72                 /// </returns>\r
73                 internal static DataBlock[] getDataBlocks(sbyte[] rawCodewords, Version version, ErrorCorrectionLevel ecLevel)\r
74                 {\r
75                         \r
76                         if (rawCodewords.Length != version.TotalCodewords)\r
77                         {\r
78                                 throw new System.ArgumentException();\r
79                         }\r
80                         \r
81                         // Figure out the number and size of data blocks used by this version and\r
82                         // error correction level\r
83                         Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);\r
84                         \r
85                         // First count the total number of data blocks\r
86                         int totalBlocks = 0;\r
87                         Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();\r
88                         for (int i = 0; i < ecBlockArray.Length; i++)\r
89                         {\r
90                                 totalBlocks += ecBlockArray[i].Count;\r
91                         }\r
92                         \r
93                         // Now establish DataBlocks of the appropriate size and number of data codewords\r
94                         DataBlock[] result = new DataBlock[totalBlocks];\r
95                         int numResultBlocks = 0;\r
96                         for (int j = 0; j < ecBlockArray.Length; j++)\r
97                         {\r
98                                 Version.ECB ecBlock = ecBlockArray[j];\r
99                                 for (int i = 0; i < ecBlock.Count; i++)\r
100                                 {\r
101                                         int numDataCodewords = ecBlock.DataCodewords;\r
102                                         int numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords;\r
103                                         result[numResultBlocks++] = new DataBlock(numDataCodewords, new sbyte[numBlockCodewords]);\r
104                                 }\r
105                         }\r
106                         \r
107                         // All blocks have the same amount of data, except that the last n\r
108                         // (where n may be 0) have 1 more byte. Figure out where these start.\r
109                         int shorterBlocksTotalCodewords = result[0].codewords.Length;\r
110                         int longerBlocksStartAt = result.Length - 1;\r
111                         while (longerBlocksStartAt >= 0)\r
112                         {\r
113                                 int numCodewords = result[longerBlocksStartAt].codewords.Length;\r
114                                 if (numCodewords == shorterBlocksTotalCodewords)\r
115                                 {\r
116                                         break;\r
117                                 }\r
118                                 longerBlocksStartAt--;\r
119                         }\r
120                         longerBlocksStartAt++;\r
121                         \r
122                         int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock;\r
123                         // The last elements of result may be 1 element longer;\r
124                         // first fill out as many elements as all of them have\r
125                         int rawCodewordsOffset = 0;\r
126                         for (int i = 0; i < shorterBlocksNumDataCodewords; i++)\r
127                         {\r
128                                 for (int j = 0; j < numResultBlocks; j++)\r
129                                 {\r
130                                         result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];\r
131                                 }\r
132                         }\r
133                         // Fill out the last data block in the longer ones\r
134                         for (int j = longerBlocksStartAt; j < numResultBlocks; j++)\r
135                         {\r
136                                 result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];\r
137                         }\r
138                         // Now add in error correction blocks\r
139                         int max = result[0].codewords.Length;\r
140                         for (int i = shorterBlocksNumDataCodewords; i < max; i++)\r
141                         {\r
142                                 for (int j = 0; j < numResultBlocks; j++)\r
143                                 {\r
144                                         int iOffset = j < longerBlocksStartAt?i:i + 1;\r
145                                         result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];\r
146                                 }\r
147                         }\r
148                         return result;\r
149                 }\r
150         }\r
151 }