qzxing/source/zxing/qrcode/decoder/DataBlock.cpp

119 lines
4.0 KiB
C++
Raw Normal View History

/*
* 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;
}
}
}