Tiny style bits
[zxing.git] / core / src / com / google / zxing / qrcode / decoder / DataBlock.java
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 \r
17 package com.google.zxing.qrcode.decoder;\r
18 \r
19 /**\r
20  * <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  * @author Sean Owen\r
25  */\r
26 final class DataBlock {\r
27 \r
28   private final int numDataCodewords;\r
29   private final byte[] codewords;\r
30 \r
31   private DataBlock(int numDataCodewords, byte[] codewords) {\r
32     this.numDataCodewords = numDataCodewords;\r
33     this.codewords = codewords;\r
34   }\r
35 \r
36   /**\r
37    * <p>When QR Codes use multiple data blocks, they are actually interleaved.\r
38    * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This\r
39    * method will separate the data into original blocks.</p>\r
40    *\r
41    * @param rawCodewords bytes as read directly from the QR Code\r
42    * @param version version of the QR Code\r
43    * @param ecLevel error-correction level of the QR Code\r
44    * @return {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the\r
45    *         QR Code\r
46    */\r
47   static DataBlock[] getDataBlocks(byte[] rawCodewords,\r
48                                    Version version,\r
49                                    ErrorCorrectionLevel ecLevel) {\r
50 \r
51     if (rawCodewords.length != version.getTotalCodewords()) {\r
52       throw new IllegalArgumentException();\r
53     }\r
54 \r
55     // Figure out the number and size of data blocks used by this version and\r
56     // error correction level\r
57     Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);\r
58 \r
59     // First count the total number of data blocks\r
60     int totalBlocks = 0;\r
61     Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();\r
62     for (int i = 0; i < ecBlockArray.length; i++) {\r
63       totalBlocks += ecBlockArray[i].getCount();\r
64     }\r
65 \r
66     // Now establish DataBlocks of the appropriate size and number of data codewords\r
67     DataBlock[] result = new DataBlock[totalBlocks];\r
68     int numResultBlocks = 0;\r
69     for (int j = 0; j < ecBlockArray.length; j++) {\r
70       Version.ECB ecBlock = ecBlockArray[j];\r
71       for (int i = 0; i < ecBlock.getCount(); i++) {\r
72         int numDataCodewords = ecBlock.getDataCodewords();\r
73         int numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;\r
74         result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);\r
75       }\r
76     }\r
77 \r
78     // All blocks have the same amount of data, except that the last n\r
79     // (where n may be 0) have 1 more byte. Figure out where these start.\r
80     int shorterBlocksTotalCodewords = result[0].codewords.length;\r
81     int longerBlocksStartAt = result.length - 1;\r
82     while (longerBlocksStartAt >= 0) {\r
83       int numCodewords = result[longerBlocksStartAt].codewords.length;\r
84       if (numCodewords == shorterBlocksTotalCodewords) {\r
85         break;\r
86       }\r
87       longerBlocksStartAt--;\r
88     }\r
89     longerBlocksStartAt++;\r
90 \r
91     int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();\r
92     // The last elements of result may be 1 element longer;\r
93     // first fill out as many elements as all of them have\r
94     int rawCodewordsOffset = 0;\r
95     for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\r
96       for (int j = 0; j < numResultBlocks; j++) {\r
97         result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];\r
98       }\r
99     }\r
100     // Fill out the last data block in the longer ones\r
101     for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {\r
102       result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];\r
103     }\r
104     // Now add in error correction blocks\r
105     int max = result[0].codewords.length;\r
106     for (int i = shorterBlocksNumDataCodewords; i < max; i++) {\r
107       for (int j = 0; j < numResultBlocks; j++) {\r
108         int iOffset = j < longerBlocksStartAt ? i : i + 1;\r
109         result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];\r
110       }\r
111     }\r
112     return result;\r
113   }\r
114 \r
115   int getNumDataCodewords() {\r
116     return numDataCodewords;\r
117   }\r
118 \r
119   byte[] getCodewords() {\r
120     return codewords;\r
121   }\r
122 \r
123 }\r