Added code for the Data Matrix decoder.
[zxing.git] / core / src / com / google / zxing / datamatrix / decoder / DataBlock.java
1 /*\r
2  * Copyright 2008 Google Inc.\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.datamatrix.decoder;\r
18 \r
19 /**\r
20  * <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix 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 bbrown@google.com (Brian Brown)\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 Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.\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 Data Matrix Code\r
42    * @param version version of the Data Matrix Code\r
43    * @return {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the\r
44    *         Data Matrix Code\r
45    */\r
46   static DataBlock[] getDataBlocks(byte[] rawCodewords,\r
47                                    Version version) {\r
48     // Figure out the number and size of data blocks used by this version\r
49     Version.ECBlocks ecBlocks = version.getECBlocks();\r
50 \r
51     // First count the total number of data blocks\r
52     int totalBlocks = 0;\r
53     Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();\r
54     for (int i = 0; i < ecBlockArray.length; i++) {\r
55       totalBlocks += ecBlockArray[i].getCount();\r
56     }\r
57 \r
58     // Now establish DataBlocks of the appropriate size and number of data codewords\r
59     DataBlock[] result = new DataBlock[totalBlocks];\r
60     int numResultBlocks = 0;\r
61     for (int j = 0; j < ecBlockArray.length; j++) {\r
62       Version.ECB ecBlock = ecBlockArray[j];\r
63       for (int i = 0; i < ecBlock.getCount(); i++) {\r
64         int numDataCodewords = ecBlock.getDataCodewords();\r
65         int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\r
66         result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);\r
67       }\r
68     }\r
69 \r
70     // All blocks have the same amount of data, except that the last n\r
71     // (where n may be 0) have 1 less byte. Figure out where these start.\r
72     // TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144\r
73     int longerBlocksTotalCodewords = result[0].codewords.length;\r
74     int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1;\r
75 \r
76     int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.getECCodewords();\r
77     int shorterBlocksNumDataCodewords = longerBlocksNumDataCodewords - 1;\r
78     // The last elements of result may be 1 element shorter for 144 matrix\r
79     // first fill out as many elements as all of them have minus 1\r
80     int rawCodewordsOffset = 0;\r
81     for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\r
82       for (int j = 0; j < numResultBlocks; j++) {\r
83         result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];\r
84       }\r
85     }\r
86     \r
87     // Fill out the last data block in the longer ones\r
88     boolean specialVersion = version.getVersionNumber() == 24;\r
89     int numLongerBlocks = specialVersion ? 8 : numResultBlocks;\r
90     for (int j = 0; j < numLongerBlocks; j++) {\r
91       result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++];\r
92     }\r
93     \r
94     // Now add in error correction blocks\r
95     int max = result[0].codewords.length;\r
96     for (int i = longerBlocksNumDataCodewords; i < max; i++) {\r
97       for (int j = 0; j < numResultBlocks; j++) {\r
98         int iOffset = (specialVersion && j > 7) ? i - 1 : i;\r
99         result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];\r
100       }\r
101     }\r
102 \r
103     if (rawCodewordsOffset != rawCodewords.length) {\r
104       throw new IllegalStateException();\r
105     }\r
106 \r
107     return result;\r
108   }\r
109 \r
110   int getNumDataCodewords() {\r
111     return numDataCodewords;\r
112   }\r
113 \r
114   byte[] getCodewords() {\r
115     return codewords;\r
116   }\r
117 \r
118 }\r