Many changes to the C++ port.
[zxing.git] / cpp / core / src / zxing / qrcode / decoder / DataBlock.cpp
diff --git a/cpp/core/src/zxing/qrcode/decoder/DataBlock.cpp b/cpp/core/src/zxing/qrcode/decoder/DataBlock.cpp
new file mode 100644 (file)
index 0000000..1ea6602
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *  DataBlock.cpp
+ *  zxing
+ *
+ *  Created by Christian Brunschen on 19/05/2008.
+ *  Copyright 2008 ZXing authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zxing/qrcode/decoder/DataBlock.h>
+#include <zxing/common/IllegalArgumentException.h>
+
+namespace zxing {
+namespace qrcode {
+
+using namespace std;
+
+DataBlock::DataBlock(int numDataCodewords, ArrayRef<unsigned char> codewords) :
+    numDataCodewords_(numDataCodewords), codewords_(codewords) {
+}
+
+int DataBlock::getNumDataCodewords() {
+  return numDataCodewords_;
+}
+
+ArrayRef<unsigned char> DataBlock::getCodewords() {
+  return codewords_;
+}
+
+
+std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version,
+    ErrorCorrectionLevel &ecLevel) {
+
+
+  // Figure out the number and size of data blocks used by this version and
+  // error correction level
+  ECBlocks &ecBlocks = version->getECBlocksForLevel(ecLevel);
+
+
+  // First count the total number of data blocks
+  int totalBlocks = 0;
+  vector<ECB*> ecBlockArray = ecBlocks.getECBlocks();
+  for (size_t i = 0; i < ecBlockArray.size(); i++) {
+    totalBlocks += ecBlockArray[i]->getCount();
+  }
+
+  // Now establish DataBlocks of the appropriate size and number of data codewords
+  std::vector<Ref<DataBlock> > result(totalBlocks);
+  int numResultBlocks = 0;
+  for (size_t j = 0; j < ecBlockArray.size(); j++) {
+    ECB *ecBlock = ecBlockArray[j];
+    for (int i = 0; i < ecBlock->getCount(); i++) {
+      int numDataCodewords = ecBlock->getDataCodewords();
+      int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;
+      ArrayRef<unsigned char> buffer(numBlockCodewords);
+      Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer));
+      result[numResultBlocks++] = blockRef;
+    }
+  }
+
+  // All blocks have the same amount of data, except that the last n
+  // (where n may be 0) have 1 more byte. Figure out where these start.
+  int shorterBlocksTotalCodewords = result[0]->codewords_.size();
+  int longerBlocksStartAt = result.size() - 1;
+  while (longerBlocksStartAt >= 0) {
+    int numCodewords = result[longerBlocksStartAt]->codewords_.size();
+    if (numCodewords == shorterBlocksTotalCodewords) {
+      break;
+    }
+    if (numCodewords != shorterBlocksTotalCodewords + 1) {
+      throw IllegalArgumentException("Data block sizes differ by more than 1");
+    }
+    longerBlocksStartAt--;
+  }
+  longerBlocksStartAt++;
+
+  int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewords();
+  // The last elements of result may be 1 element longer;
+  // first fill out as many elements as all of them have
+  int rawCodewordsOffset = 0;
+  for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
+    for (int j = 0; j < numResultBlocks; j++) {
+      result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++];
+    }
+  }
+  // Fill out the last data block in the longer ones
+  for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {
+    result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
+  }
+  // Now add in error correction blocks
+  int max = result[0]->codewords_.size();
+  for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
+    for (int j = 0; j < numResultBlocks; j++) {
+      int iOffset = j < longerBlocksStartAt ? i : i + 1;
+      result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++];
+    }
+  }
+
+  if ((size_t)rawCodewordsOffset != rawCodewords.size()) {
+    throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length");
+  }
+
+  return result;
+}
+
+}
+}