git-svn-id: http://zxing.googlecode.com/svn/trunk@2 59b500cc-1b3d-0410-9834-0bbf25fbcc57
[zxing.git] / src / com / google / zxing / qrcode / decoder / DataBlock.java
1 /*\r
2  * Copyright 2007 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.qrcode.decoder;\r
18 \r
19 /**\r
20  * @author srowen@google.com (Sean Owen)\r
21  */\r
22 final class DataBlock {\r
23 \r
24   private final int numDataCodewords;\r
25   private final byte[] codewords;\r
26 \r
27   private DataBlock(int numDataCodewords, byte[] codewords) {\r
28     this.numDataCodewords = numDataCodewords;\r
29     this.codewords = codewords;\r
30   }\r
31 \r
32   static DataBlock[] getDataBlocks(byte[] rawCodewords,\r
33                                    Version version,\r
34                                    ErrorCorrectionLevel ecLevel) {\r
35     Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);\r
36     int totalBlocks = 0;\r
37     Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();\r
38     for (int i = 0; i < ecBlockArray.length; i++) {\r
39       totalBlocks += ecBlockArray[i].getCount();\r
40     }\r
41     DataBlock[] result = new DataBlock[totalBlocks];\r
42     int numResultBlocks = 0;\r
43     for (int j = 0; j < ecBlockArray.length; j++) {\r
44       Version.ECB ecBlock = ecBlockArray[j];\r
45       for (int i = 0; i < ecBlock.getCount(); i++) {\r
46         int numDataCodewords = ecBlock.getDataCodewords();\r
47         int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\r
48         result[numResultBlocks++] =\r
49             new DataBlock(numDataCodewords, new byte[numBlockCodewords]);\r
50       }\r
51     }\r
52 \r
53     // All blocks have the same amount of data, except that the last n\r
54     // (where n may be 0) have 1 more byte. Figure out where these start.\r
55     int shorterBlocksTotalCodewords = result[0].codewords.length;\r
56     int longerBlocksStartAt = result.length - 1;\r
57     while (longerBlocksStartAt >= 0) {\r
58       int numCodewords =\r
59           result[longerBlocksStartAt].codewords.length;\r
60       if (numCodewords == shorterBlocksTotalCodewords) {\r
61         break;\r
62       }\r
63       if (numCodewords != shorterBlocksTotalCodewords + 1) {\r
64         throw new IllegalStateException(\r
65             "Data block sizes differ by more than 1");\r
66       }\r
67       longerBlocksStartAt--;\r
68     }\r
69     longerBlocksStartAt++;\r
70 \r
71     int shorterBlocksNumDataCodewords =\r
72         shorterBlocksTotalCodewords - ecBlocks.getECCodewords();\r
73     // The last elements of result may be 1 element longer;\r
74     // first fill out as many elements as all of them have\r
75     int rawCodewordsOffset = 0;\r
76     for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\r
77       for (int j = 0; j < numResultBlocks; j++) {\r
78         result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];\r
79       }\r
80     }\r
81     // Fill out the last data block in the longer ones\r
82     for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {\r
83       result[j].codewords[shorterBlocksNumDataCodewords] =\r
84           rawCodewords[rawCodewordsOffset++];\r
85     }\r
86     // Now add in error correction blocks\r
87     int max = result[0].codewords.length;\r
88     for (int i = shorterBlocksNumDataCodewords; i < max; i++) {\r
89       for (int j = 0; j < numResultBlocks; j++) {\r
90         int iOffset = j < longerBlocksStartAt ? i : i + 1;\r
91         result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];\r
92       }\r
93     }\r
94 \r
95     if (rawCodewordsOffset != rawCodewords.length) {\r
96       throw new IllegalStateException();\r
97     }\r
98 \r
99     return result;\r
100   }\r
101 \r
102   int getNumDataCodewords() {\r
103     return numDataCodewords;\r
104   }\r
105 \r
106   byte[] getCodewords() {\r
107     return codewords;\r
108   }\r
109 \r
110 }\r