C# port, add datamatrix code
[zxing.git] / csharp / datamatrix / decoder / DataBlock.cs
diff --git a/csharp/datamatrix/decoder/DataBlock.cs b/csharp/datamatrix/decoder/DataBlock.cs
new file mode 100644 (file)
index 0000000..8e4893e
--- /dev/null
@@ -0,0 +1,124 @@
+/*\r
+ * Copyright 2008 ZXing authors\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+\r
+namespace com.google.zxing.datamatrix.decoder\r
+{\r
+\r
+    /**\r
+     * <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into\r
+     * multiple blocks, each of which is a unit of data and error-correction codewords. Each\r
+     * is represented by an instance of this class.</p>\r
+     *\r
+     * @author bbrown@google.com (Brian Brown)\r
+     */\r
+    public sealed class DataBlock\r
+    {\r
+          private  int numDataCodewords;\r
+          private  sbyte[] codewords;\r
+\r
+          private DataBlock(int numDataCodewords, sbyte[] codewords) {\r
+            this.numDataCodewords = numDataCodewords;\r
+            this.codewords = codewords;\r
+          }\r
+\r
+          /**\r
+           * <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.\r
+           * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This\r
+           * method will separate the data into original blocks.</p>\r
+           *\r
+           * @param rawCodewords bytes as read directly from the Data Matrix Code\r
+           * @param version version of the Data Matrix Code\r
+           * @return {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the\r
+           *         Data Matrix Code\r
+           */\r
+          public static DataBlock[] getDataBlocks(sbyte[] rawCodewords,\r
+                                           Version version) {\r
+            // Figure out the number and size of data blocks used by this version\r
+            Version.ECBlocks ecBlocks = version.getECBlocks();\r
+\r
+            // First count the total number of data blocks\r
+            int totalBlocks = 0;\r
+            Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();\r
+            for (int i = 0; i < ecBlockArray.Length; i++) {\r
+              totalBlocks += ecBlockArray[i].getCount();\r
+            }\r
+\r
+            // Now establish DataBlocks of the appropriate size and number of data codewords\r
+            DataBlock[] result = new DataBlock[totalBlocks];\r
+            int numResultBlocks = 0;\r
+            for (int j = 0; j < ecBlockArray.Length; j++) {\r
+              Version.ECB ecBlock = ecBlockArray[j];\r
+              for (int i = 0; i < ecBlock.getCount(); i++) {\r
+                int numDataCodewords = ecBlock.getDataCodewords();\r
+                int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\r
+                result[numResultBlocks++] = new DataBlock(numDataCodewords, new sbyte[numBlockCodewords]);\r
+              }\r
+            }\r
+\r
+            // All blocks have the same amount of data, except that the last n\r
+            // (where n may be 0) have 1 less byte. Figure out where these start.\r
+            // TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144\r
+            int longerBlocksTotalCodewords = result[0].codewords.Length;\r
+            //int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1;\r
+\r
+            int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.getECCodewords();\r
+            int shorterBlocksNumDataCodewords = longerBlocksNumDataCodewords - 1;\r
+            // The last elements of result may be 1 element shorter for 144 matrix\r
+            // first fill out as many elements as all of them have minus 1\r
+            int rawCodewordsOffset = 0;\r
+            for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\r
+              for (int j = 0; j < numResultBlocks; j++) {\r
+                result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];\r
+              }\r
+            }\r
+            \r
+            // Fill out the last data block in the longer ones\r
+            bool specialVersion = version.getVersionNumber() == 24;\r
+            int numLongerBlocks = specialVersion ? 8 : numResultBlocks;\r
+            for (int j = 0; j < numLongerBlocks; j++) {\r
+              result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++];\r
+            }\r
+            \r
+            // Now add in error correction blocks\r
+            int max = result[0].codewords.Length;\r
+            for (int i = longerBlocksNumDataCodewords; i < max; i++) {\r
+              for (int j = 0; j < numResultBlocks; j++) {\r
+                int iOffset = (specialVersion && j > 7) ? i - 1 : i;\r
+                result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];\r
+              }\r
+            }\r
+\r
+            if (rawCodewordsOffset != rawCodewords.Length) {\r
+              throw new ArgumentException();\r
+            }\r
+\r
+            return result;\r
+          }\r
+\r
+          public int getNumDataCodewords() {\r
+            return numDataCodewords;\r
+          }\r
+\r
+          public sbyte[] getCodewords() {\r
+            return codewords;\r
+          }\r
+    }\r
+}\r