mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Port r1623 changes to C++
This provide C++ support for Hanzi from issue 582. With it the C++ qrcode blackbox test results again match the Java results. The changes are mostly a re-port of various pieces of the Java code for supporting modes and bit stream parsing in QR codes. It expands the modes/parsing including ECI and FNC, refactors StringUtils as was done in Java, and makes DecoderResult include the fields that the Java code has. Although the non-qrcode blackbox tests don't all match the Java code (a known issue) the entire blackbox suite was run under valgrind and has no errors, including invalid memory references and leaks. This commit also includes a few cleanups for things like files that had mixed line endings, i.e., a combination of LF and CR-LF. git-svn-id: https://zxing.googlecode.com/svn/trunk@1966 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
492d773f59
commit
2c787d8440
14
cpp/.valgrind.supp
Normal file
14
cpp/.valgrind.supp
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
zxing::common::CharacterSetECI::init_tables
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
...
|
||||
fun:_ZN5zxing6common15CharacterSetECI11init_tablesEv
|
||||
}
|
||||
|
||||
{
|
||||
ImageMagick
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:AcquireImage
|
||||
}
|
1
cpp/.valgrindrc
Normal file
1
cpp/.valgrindrc
Normal file
|
@ -0,0 +1 @@
|
|||
--memcheck:leak-check=full --suppressions=.valgrind.supp --gen-suppressions=all
|
|
@ -28,7 +28,7 @@ def all_files(dir, ext='.cpp', level=5):
|
|||
|
||||
|
||||
|
||||
magick_include = ['/usr/include/ImageMagick/']
|
||||
magick_include = ['/usr/include/ImageMagick/', '/opt/local/include/ImageMagick/']
|
||||
magick_libs = ['Magick++', 'MagickWand', 'MagickCore']
|
||||
|
||||
cppunit_libs = ['cppunit']
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <zxing/common/IllegalArgumentException.h>
|
||||
namespace zxing {
|
||||
|
||||
const DecodeHintType DecodeHints::CHARACTER_SET;
|
||||
|
||||
const DecodeHints DecodeHints::PRODUCT_HINT(
|
||||
BARCODEFORMAT_UPC_E_HINT |
|
||||
BARCODEFORMAT_UPC_A_HINT |
|
||||
|
|
|
@ -30,6 +30,12 @@ class DecodeHints {
|
|||
|
||||
private:
|
||||
|
||||
DecodeHintType hints;
|
||||
|
||||
Ref<ResultPointCallback> callback;
|
||||
|
||||
public:
|
||||
|
||||
static const DecodeHintType BARCODEFORMAT_QR_CODE_HINT = 1 << BarcodeFormat_QR_CODE;
|
||||
static const DecodeHintType BARCODEFORMAT_DATA_MATRIX_HINT = 1 << BarcodeFormat_DATA_MATRIX;
|
||||
static const DecodeHintType BARCODEFORMAT_UPC_E_HINT = 1 << BarcodeFormat_UPC_E;
|
||||
|
@ -39,14 +45,9 @@ class DecodeHints {
|
|||
static const DecodeHintType BARCODEFORMAT_CODE_128_HINT = 1 << BarcodeFormat_CODE_128;
|
||||
static const DecodeHintType BARCODEFORMAT_CODE_39_HINT = 1 << BarcodeFormat_CODE_39;
|
||||
static const DecodeHintType BARCODEFORMAT_ITF_HINT = 1 << BarcodeFormat_ITF;
|
||||
static const DecodeHintType CHARACTER_SET = 1 << 30;
|
||||
static const DecodeHintType TRYHARDER_HINT = 1 << 31;
|
||||
|
||||
DecodeHintType hints;
|
||||
|
||||
Ref<ResultPointCallback> callback;
|
||||
|
||||
public:
|
||||
|
||||
static const DecodeHints PRODUCT_HINT;
|
||||
static const DecodeHints ONED_HINT;
|
||||
static const DecodeHints DEFAULT_HINT;
|
||||
|
|
|
@ -1,16 +1,31 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* Exception.cpp
|
||||
* ZXing
|
||||
*
|
||||
* Created by Christian Brunschen on 03/06/2008.
|
||||
* Copyright 2008 ZXing authors All rights reserved.
|
||||
* Copyright 2008-2011 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/Exception.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
Exception::Exception() {}
|
||||
|
||||
Exception::Exception(const char *msg) :
|
||||
message(msg) {
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ private:
|
|||
std::string message;
|
||||
|
||||
public:
|
||||
Exception();
|
||||
Exception(const char *msg);
|
||||
virtual const char* what() const throw();
|
||||
virtual ~Exception() throw();
|
||||
|
|
35
cpp/core/src/zxing/FormatException.cpp
Normal file
35
cpp/core/src/zxing/FormatException.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* FormatException.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Christian Brunschen on 13/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/FormatException.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
FormatException::FormatException() {}
|
||||
|
||||
FormatException::FormatException(const char *msg) :
|
||||
ReaderException(msg) {
|
||||
}
|
||||
|
||||
FormatException::~FormatException() throw() {
|
||||
}
|
||||
|
||||
}
|
35
cpp/core/src/zxing/FormatException.h
Normal file
35
cpp/core/src/zxing/FormatException.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef __FORMAT_EXCEPTION_H__
|
||||
#define __FORMAT_EXCEPTION_H__
|
||||
|
||||
/*
|
||||
* FormatException.h
|
||||
* zxing
|
||||
*
|
||||
* Copyright 2010 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/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class FormatException : public ReaderException {
|
||||
public:
|
||||
FormatException();
|
||||
FormatException(const char *msg);
|
||||
~FormatException() throw();
|
||||
};
|
||||
|
||||
}
|
||||
#endif // __FORMAT_EXCEPTION_H__
|
|
@ -89,7 +89,7 @@ namespace zxing {
|
|||
for (unsigned int i = 0; i < readers_.size(); i++) {
|
||||
try {
|
||||
return readers_[i]->decode(image, hints_);
|
||||
} catch (ReaderException re) {
|
||||
} catch (ReaderException const& re) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* ReaderException.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Christian Brunschen on 13/05/2008.
|
||||
* Copyright 2008 ZXing authors All rights reserved.
|
||||
* Copyright 2008-2011 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.
|
||||
|
@ -22,6 +23,8 @@
|
|||
|
||||
namespace zxing {
|
||||
|
||||
ReaderException::ReaderException() {}
|
||||
|
||||
ReaderException::ReaderException(const char *msg) :
|
||||
Exception(msg) {
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace zxing {
|
|||
|
||||
class ReaderException : public Exception {
|
||||
public:
|
||||
ReaderException();
|
||||
ReaderException(const char *msg);
|
||||
~ReaderException() throw();
|
||||
};
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T> class ArrayRef {
|
||||
template<typename T> class ArrayRef : public Counted {
|
||||
private:
|
||||
public:
|
||||
Array<T> *array_;
|
||||
|
|
87
cpp/core/src/zxing/common/CharacterSetECI.cpp
Normal file
87
cpp/core/src/zxing/common/CharacterSetECI.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* Copyright 2008-2011 ZXing authors
|
||||
*
|
||||
* 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/common/CharacterSetECI.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
using zxing::common::CharacterSetECI;
|
||||
using zxing::IllegalArgumentException;
|
||||
|
||||
std::map<int, CharacterSetECI*> CharacterSetECI::VALUE_TO_ECI;
|
||||
std::map<std::string, CharacterSetECI*> CharacterSetECI::NAME_TO_ECI;
|
||||
|
||||
const bool CharacterSetECI::inited = CharacterSetECI::init_tables();
|
||||
|
||||
bool CharacterSetECI::init_tables() {
|
||||
addCharacterSet(0, "Cp437");
|
||||
{ char const* s[] = {"ISO8859_1", "ISO-8859-1", 0};
|
||||
addCharacterSet(1, s); }
|
||||
addCharacterSet(2, "Cp437");
|
||||
{ char const* s[] = {"ISO8859_1", "ISO-8859-1", 0};
|
||||
addCharacterSet(3, s); }
|
||||
addCharacterSet(4, "ISO8859_2");
|
||||
addCharacterSet(5, "ISO8859_3");
|
||||
addCharacterSet(6, "ISO8859_4");
|
||||
addCharacterSet(7, "ISO8859_5");
|
||||
addCharacterSet(8, "ISO8859_6");
|
||||
addCharacterSet(9, "ISO8859_7");
|
||||
addCharacterSet(10, "ISO8859_8");
|
||||
addCharacterSet(11, "ISO8859_9");
|
||||
addCharacterSet(12, "ISO8859_10");
|
||||
addCharacterSet(13, "ISO8859_11");
|
||||
addCharacterSet(15, "ISO8859_13");
|
||||
addCharacterSet(16, "ISO8859_14");
|
||||
addCharacterSet(17, "ISO8859_15");
|
||||
addCharacterSet(18, "ISO8859_16");
|
||||
{ char const* s[] = {"SJIS", "Shift_JIS", 0};
|
||||
addCharacterSet(20, s ); }
|
||||
return true;
|
||||
}
|
||||
|
||||
CharacterSetECI::CharacterSetECI(int value, char const* encodingName_)
|
||||
: ECI(value), encodingName(encodingName_) {}
|
||||
|
||||
char const* CharacterSetECI::getEncodingName() {
|
||||
return encodingName;
|
||||
}
|
||||
|
||||
void CharacterSetECI::addCharacterSet(int value, char const* encodingName) {
|
||||
CharacterSetECI* eci = new CharacterSetECI(value, encodingName);
|
||||
VALUE_TO_ECI[value] = eci; // can't use valueOf
|
||||
NAME_TO_ECI[string(encodingName)] = eci;
|
||||
}
|
||||
|
||||
void CharacterSetECI::addCharacterSet(int value, char const* const* encodingNames) {
|
||||
CharacterSetECI* eci = new CharacterSetECI(value, encodingNames[0]);
|
||||
VALUE_TO_ECI[value] = eci;
|
||||
for (int i = 0; encodingNames[i]; i++) {
|
||||
NAME_TO_ECI[string(encodingNames[i])] = eci;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterSetECI* CharacterSetECI::getCharacterSetECIByValue(int value) {
|
||||
if (value < 0 || value >= 900) {
|
||||
throw IllegalArgumentException("Bad ECI value: " + value);
|
||||
}
|
||||
return VALUE_TO_ECI[value];
|
||||
}
|
||||
|
||||
CharacterSetECI* CharacterSetECI::getCharacterSetECIByName(string const& name) {
|
||||
return NAME_TO_ECI[name];
|
||||
}
|
53
cpp/core/src/zxing/common/CharacterSetECI.h
Normal file
53
cpp/core/src/zxing/common/CharacterSetECI.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
|
||||
#ifndef __CHARACTERSET_ECI__
|
||||
#define __CHARACTERSET_ECI__
|
||||
|
||||
/*
|
||||
* Copyright 2008-2011 ZXing authors
|
||||
*
|
||||
* 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 <map>
|
||||
#include <zxing/common/ECI.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace common {
|
||||
class CharacterSetECI;
|
||||
}
|
||||
}
|
||||
|
||||
class zxing::common::CharacterSetECI : public ECI {
|
||||
private:
|
||||
static std::map<int, CharacterSetECI*> VALUE_TO_ECI;
|
||||
static std::map<std::string, CharacterSetECI*> NAME_TO_ECI;
|
||||
static const bool inited;
|
||||
static bool init_tables();
|
||||
|
||||
char const* const encodingName;
|
||||
|
||||
CharacterSetECI(int value, char const* encodingName);
|
||||
|
||||
static void addCharacterSet(int value, char const* encodingName);
|
||||
static void addCharacterSet(int value, char const* const* encodingNames);
|
||||
|
||||
public:
|
||||
char const* getEncodingName();
|
||||
|
||||
static CharacterSetECI* getCharacterSetECIByValue(int value);
|
||||
static CharacterSetECI* getCharacterSetECIByName(std::string const& name);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,9 +1,10 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* DecoderResult.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Christian Brunschen on 20/05/2008.
|
||||
* Copyright 2008 ZXing authors All rights reserved.
|
||||
* Copyright 2008-2011 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.
|
||||
|
@ -20,11 +21,21 @@
|
|||
|
||||
#include <zxing/common/DecoderResult.h>
|
||||
|
||||
namespace zxing {
|
||||
using namespace std;
|
||||
using namespace zxing;
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes, Ref<String> text) :
|
||||
rawBytes_(rawBytes), text_(text) {
|
||||
}
|
||||
DecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes,
|
||||
Ref<String> text,
|
||||
ArrayRef< ArrayRef<unsigned char> >& byteSegments,
|
||||
string const& ecLevel) :
|
||||
rawBytes_(rawBytes),
|
||||
text_(text),
|
||||
byteSegments_(byteSegments),
|
||||
ecLevel_(ecLevel) {}
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<unsigned char> rawBytes,
|
||||
Ref<String> text)
|
||||
: rawBytes_(rawBytes), text_(text) {}
|
||||
|
||||
ArrayRef<unsigned char> DecoderResult::getRawBytes() {
|
||||
return rawBytes_;
|
||||
|
@ -33,5 +44,3 @@ ArrayRef<unsigned char> DecoderResult::getRawBytes() {
|
|||
Ref<String> DecoderResult::getText() {
|
||||
return text_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,9 +31,17 @@ class DecoderResult : public Counted {
|
|||
private:
|
||||
ArrayRef<unsigned char> rawBytes_;
|
||||
Ref<String> text_;
|
||||
ArrayRef< ArrayRef<unsigned char> > byteSegments_;
|
||||
std::string ecLevel_;
|
||||
|
||||
public:
|
||||
DecoderResult(ArrayRef<unsigned char> rawBytes,
|
||||
Ref<String> text,
|
||||
ArrayRef< ArrayRef<unsigned char> >& byteSegments,
|
||||
std::string const& ecLevel);
|
||||
|
||||
DecoderResult(ArrayRef<unsigned char> rawBytes, Ref<String> text);
|
||||
|
||||
ArrayRef<unsigned char> getRawBytes();
|
||||
Ref<String> getText();
|
||||
};
|
||||
|
|
39
cpp/core/src/zxing/common/ECI.cpp
Normal file
39
cpp/core/src/zxing/common/ECI.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* Copyright 2008-2011 ZXing authors
|
||||
*
|
||||
* 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/common/ECI.h>
|
||||
#include <zxing/common/CharacterSetECI.h>
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
|
||||
using zxing::common::ECI;
|
||||
using zxing::IllegalArgumentException;
|
||||
|
||||
ECI::ECI(int value_) : value(value_) {}
|
||||
|
||||
int ECI::getValue() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
ECI* ECI::getECIByValue(int value) {
|
||||
if (value < 0 || value > 999999) {
|
||||
throw IllegalArgumentException("Bad ECI value: " + value);
|
||||
}
|
||||
if (value < 900) { // Character set ECIs use 000000 - 000899
|
||||
return CharacterSetECI::getCharacterSetECIByValue(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
40
cpp/core/src/zxing/common/ECI.h
Normal file
40
cpp/core/src/zxing/common/ECI.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
|
||||
#ifndef __ECI__
|
||||
#define __ECI__
|
||||
|
||||
/*
|
||||
* Copyright 2008-2011 ZXing authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace zxing {
|
||||
namespace common {
|
||||
class ECI;
|
||||
}
|
||||
}
|
||||
class zxing::common::ECI {
|
||||
private:
|
||||
const int value;
|
||||
|
||||
protected:
|
||||
ECI(int value);
|
||||
|
||||
public:
|
||||
int getValue() const;
|
||||
|
||||
static ECI* getECIByValue(int value);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -19,8 +19,8 @@
|
|||
*/
|
||||
|
||||
#include <zxing/common/GlobalHistogramBinarizer.h>
|
||||
|
||||
#include <zxing/common/IllegalArgumentException.h>
|
||||
#include <zxing/common/Array.h>
|
||||
|
||||
namespace zxing {
|
||||
using namespace std;
|
||||
|
@ -107,7 +107,8 @@ Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {
|
|||
// Quickly calculates the histogram by sampling four rows from the image.
|
||||
// This proved to be more robust on the blackbox tests than sampling a
|
||||
// diagonal as we used to do.
|
||||
unsigned char* row = new unsigned char[width];
|
||||
ArrayRef<unsigned char> ref (width);
|
||||
unsigned char* row = &ref[0];
|
||||
for (int y = 1; y < 5; y++) {
|
||||
int rownum = height * y / 5;
|
||||
int right = (width << 2) / 5;
|
||||
|
@ -130,7 +131,7 @@ Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {
|
|||
}
|
||||
|
||||
cached_matrix_ = matrix_ref;
|
||||
delete [] row;
|
||||
// delete [] row;
|
||||
return matrix_ref;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ Ref<BitMatrix> HybridBinarizer::getBlackMatrix() {
|
|||
calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix);
|
||||
matrix_ = newMatrix;
|
||||
|
||||
// N.B.: these deletes are inadequate if anything between the new and this point can throw.
|
||||
// As of this writing, it doesn't look like they do.
|
||||
|
||||
delete [] blackPoints;
|
||||
delete [] luminances;
|
||||
} else {
|
||||
|
|
175
cpp/core/src/zxing/common/StringUtils.cpp
Normal file
175
cpp/core/src/zxing/common/StringUtils.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2011 ZXing authors
|
||||
*
|
||||
* 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/common/StringUtils.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace zxing;
|
||||
using namespace zxing::common;
|
||||
|
||||
// N.B.: these are the iconv strings for at least some versions of iconv
|
||||
|
||||
char const* const StringUtils::PLATFORM_DEFAULT_ENCODING = "UTF-8";
|
||||
char const* const StringUtils::ASCII = "ASCII";
|
||||
char const* const StringUtils::SHIFT_JIS = "SHIFT_JIS";
|
||||
char const* const StringUtils::GB2312 = "GBK";
|
||||
char const* const StringUtils::EUC_JP = "EUC-JP";
|
||||
char const* const StringUtils::UTF8 = "UTF-8";
|
||||
char const* const StringUtils::ISO88591 = "ISO8859-1";
|
||||
const bool StringUtils::ASSUME_SHIFT_JIS = false;
|
||||
|
||||
string
|
||||
StringUtils::guessEncoding(unsigned char* bytes, int length, Hashtable const& hints) {
|
||||
Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET);
|
||||
if (i != hints.end()) {
|
||||
return i->second;
|
||||
}
|
||||
// Does it start with the UTF-8 byte order mark? then guess it's UTF-8
|
||||
if (length > 3 &&
|
||||
bytes[0] == (unsigned char) 0xEF &&
|
||||
bytes[1] == (unsigned char) 0xBB &&
|
||||
bytes[2] == (unsigned char) 0xBF) {
|
||||
return UTF8;
|
||||
}
|
||||
// For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
|
||||
// which should be by far the most common encodings. ISO-8859-1
|
||||
// should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
|
||||
// uses this as a first byte of a two-byte character. If we see this
|
||||
// followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
|
||||
// If we see something else in that second byte, we'll make the risky guess
|
||||
// that it's UTF-8.
|
||||
bool canBeISO88591 = true;
|
||||
bool canBeShiftJIS = true;
|
||||
bool canBeUTF8 = true;
|
||||
int utf8BytesLeft = 0;
|
||||
int maybeDoubleByteCount = 0;
|
||||
int maybeSingleByteKatakanaCount = 0;
|
||||
bool sawLatin1Supplement = false;
|
||||
bool sawUTF8Start = false;
|
||||
bool lastWasPossibleDoubleByteStart = false;
|
||||
|
||||
for (int i = 0;
|
||||
i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8);
|
||||
i++) {
|
||||
|
||||
int value = bytes[i] & 0xFF;
|
||||
|
||||
// UTF-8 stuff
|
||||
if (value >= 0x80 && value <= 0xBF) {
|
||||
if (utf8BytesLeft > 0) {
|
||||
utf8BytesLeft--;
|
||||
}
|
||||
} else {
|
||||
if (utf8BytesLeft > 0) {
|
||||
canBeUTF8 = false;
|
||||
}
|
||||
if (value >= 0xC0 && value <= 0xFD) {
|
||||
sawUTF8Start = true;
|
||||
int valueCopy = value;
|
||||
while ((valueCopy & 0x40) != 0) {
|
||||
utf8BytesLeft++;
|
||||
valueCopy <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ISO-8859-1 stuff
|
||||
|
||||
if ((value == 0xC2 || value == 0xC3) && i < length - 1) {
|
||||
// This is really a poor hack. The slightly more exotic characters people might want to put in
|
||||
// a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings
|
||||
// that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF].
|
||||
int nextValue = bytes[i + 1] & 0xFF;
|
||||
if (nextValue <= 0xBF &&
|
||||
((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) {
|
||||
sawLatin1Supplement = true;
|
||||
}
|
||||
}
|
||||
if (value >= 0x7F && value <= 0x9F) {
|
||||
canBeISO88591 = false;
|
||||
}
|
||||
|
||||
// Shift_JIS stuff
|
||||
|
||||
if (value >= 0xA1 && value <= 0xDF) {
|
||||
// count the number of characters that might be a Shift_JIS single-byte Katakana character
|
||||
if (!lastWasPossibleDoubleByteStart) {
|
||||
maybeSingleByteKatakanaCount++;
|
||||
}
|
||||
}
|
||||
if (!lastWasPossibleDoubleByteStart &&
|
||||
((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) {
|
||||
canBeShiftJIS = false;
|
||||
}
|
||||
if ((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF)) {
|
||||
// These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid
|
||||
// second byte.
|
||||
if (lastWasPossibleDoubleByteStart) {
|
||||
// If we just checked this and the last byte for being a valid double-byte
|
||||
// char, don't check starting on this byte. If this and the last byte
|
||||
// formed a valid pair, then this shouldn't be checked to see if it starts
|
||||
// a double byte pair of course.
|
||||
lastWasPossibleDoubleByteStart = false;
|
||||
} else {
|
||||
// ... otherwise do check to see if this plus the next byte form a valid
|
||||
// double byte pair encoding a character.
|
||||
lastWasPossibleDoubleByteStart = true;
|
||||
if (i >= length - 1) {
|
||||
canBeShiftJIS = false;
|
||||
} else {
|
||||
int nextValue = bytes[i + 1] & 0xFF;
|
||||
if (nextValue < 0x40 || nextValue > 0xFC) {
|
||||
canBeShiftJIS = false;
|
||||
} else {
|
||||
maybeDoubleByteCount++;
|
||||
}
|
||||
// There is some conflicting information out there about which bytes can follow which in
|
||||
// double-byte Shift_JIS characters. The rule above seems to be the one that matches practice.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastWasPossibleDoubleByteStart = false;
|
||||
}
|
||||
}
|
||||
if (utf8BytesLeft > 0) {
|
||||
canBeUTF8 = false;
|
||||
}
|
||||
|
||||
// Easy -- if assuming Shift_JIS and no evidence it can't be, done
|
||||
if (canBeShiftJIS && ASSUME_SHIFT_JIS) {
|
||||
return SHIFT_JIS;
|
||||
}
|
||||
if (canBeUTF8 && sawUTF8Start) {
|
||||
return UTF8;
|
||||
}
|
||||
// Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is:
|
||||
// - If we saw
|
||||
// - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or
|
||||
// - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1),
|
||||
// - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS
|
||||
if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) {
|
||||
return SHIFT_JIS;
|
||||
}
|
||||
// Otherwise, we default to ISO-8859-1 unless we know it can't be
|
||||
if (!sawLatin1Supplement && canBeISO88591) {
|
||||
return ISO88591;
|
||||
}
|
||||
// Otherwise, we take a wild guess with platform encoding
|
||||
return PLATFORM_DEFAULT_ENCODING;
|
||||
}
|
52
cpp/core/src/zxing/common/StringUtils.h
Normal file
52
cpp/core/src/zxing/common/StringUtils.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
|
||||
#ifndef __STRING_UTILS__
|
||||
#define __STRING_UTILS__
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2011 ZXing authors
|
||||
*
|
||||
* 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 <string>
|
||||
#include <map>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace common {
|
||||
class StringUtils;
|
||||
}
|
||||
}
|
||||
|
||||
class zxing::common::StringUtils {
|
||||
private:
|
||||
static char const* const PLATFORM_DEFAULT_ENCODING;
|
||||
|
||||
StringUtils() {}
|
||||
|
||||
public:
|
||||
static char const* const ASCII;
|
||||
static char const* const SHIFT_JIS;
|
||||
static char const* const GB2312;
|
||||
static char const* const EUC_JP;
|
||||
static char const* const UTF8;
|
||||
static char const* const ISO88591;
|
||||
static const bool ASSUME_SHIFT_JIS;
|
||||
|
||||
typedef std::map<DecodeHintType, std::string> Hashtable;
|
||||
|
||||
static std::string guessEncoding(unsigned char* bytes, int length, Hashtable const& hints);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -34,7 +34,7 @@ using namespace std;
|
|||
Decoder::Decoder() :
|
||||
rsDecoder_(GF256::DATA_MATRIX_FIELD) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCodewords) {
|
||||
int numCodewords = codewordBytes->size();
|
||||
|
@ -46,7 +46,7 @@ void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCo
|
|||
|
||||
try {
|
||||
rsDecoder_.decode(codewordInts, numECCodewords);
|
||||
} catch (ReedSolomonException ex) {
|
||||
} catch (ReedSolomonException const& ex) {
|
||||
ReaderException rex(ex.what());
|
||||
throw rex;
|
||||
}
|
||||
|
@ -56,34 +56,34 @@ void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCo
|
|||
}
|
||||
}
|
||||
|
||||
Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
|
||||
// Construct a parser and read version, error-correction level
|
||||
BitMatrixParser parser(bits);
|
||||
Version *version = parser.readVersion(bits);
|
||||
|
||||
// Read codewords
|
||||
ArrayRef<unsigned char> codewords(parser.readCodewords());
|
||||
// Separate into data blocks
|
||||
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
|
||||
|
||||
// Count total number of data bytes
|
||||
int totalBytes = 0;
|
||||
for (unsigned int i = 0; i < dataBlocks.size(); i++) {
|
||||
totalBytes += dataBlocks[i]->getNumDataCodewords();
|
||||
}
|
||||
ArrayRef<unsigned char> resultBytes(totalBytes);
|
||||
int resultOffset = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for (unsigned int j = 0; j < dataBlocks.size(); j++) {
|
||||
Ref<DataBlock> dataBlock(dataBlocks[j]);
|
||||
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
|
||||
int numDataCodewords = dataBlock->getNumDataCodewords();
|
||||
correctErrors(codewordBytes, numDataCodewords);
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
resultBytes[resultOffset++] = codewordBytes[i];
|
||||
}
|
||||
}
|
||||
Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
|
||||
// Construct a parser and read version, error-correction level
|
||||
BitMatrixParser parser(bits);
|
||||
Version *version = parser.readVersion(bits);
|
||||
|
||||
// Read codewords
|
||||
ArrayRef<unsigned char> codewords(parser.readCodewords());
|
||||
// Separate into data blocks
|
||||
std::vector<Ref<DataBlock> > dataBlocks = DataBlock::getDataBlocks(codewords, version);
|
||||
|
||||
// Count total number of data bytes
|
||||
int totalBytes = 0;
|
||||
for (unsigned int i = 0; i < dataBlocks.size(); i++) {
|
||||
totalBytes += dataBlocks[i]->getNumDataCodewords();
|
||||
}
|
||||
ArrayRef<unsigned char> resultBytes(totalBytes);
|
||||
int resultOffset = 0;
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for (unsigned int j = 0; j < dataBlocks.size(); j++) {
|
||||
Ref<DataBlock> dataBlock(dataBlocks[j]);
|
||||
ArrayRef<unsigned char> codewordBytes = dataBlock->getCodewords();
|
||||
int numDataCodewords = dataBlock->getNumDataCodewords();
|
||||
correctErrors(codewordBytes, numDataCodewords);
|
||||
for (int i = 0; i < numDataCodewords; i++) {
|
||||
resultBytes[resultOffset++] = codewordBytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
DecodedBitStreamParser decodedBSParser;
|
||||
|
|
|
@ -279,7 +279,7 @@ namespace zxing {
|
|||
// Decode another code from image
|
||||
try {
|
||||
code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart);
|
||||
} catch (ReaderException re) {
|
||||
} catch (ReaderException const& re) {
|
||||
throw re;
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace zxing {
|
|||
delete [] endRange;
|
||||
ArrayRef<unsigned char> resultBytes(1);
|
||||
return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
|
||||
} catch (ReaderException re) {
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] startRange;
|
||||
delete [] endRange;
|
||||
return Ref<Result>();
|
||||
|
@ -179,7 +179,7 @@ namespace zxing {
|
|||
narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
|
||||
validateQuietZone(row, startPattern[0]);
|
||||
return startPattern;
|
||||
} catch (ReaderException re) {
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] startPattern;
|
||||
throw re;
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ namespace zxing {
|
|||
|
||||
row->reverse();
|
||||
return endPattern;
|
||||
} catch (ReaderException re) {
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] endPattern;
|
||||
row->reverse();
|
||||
throw re;
|
||||
|
|
|
@ -89,9 +89,9 @@ namespace zxing {
|
|||
// Estimate black point for this row and load it:
|
||||
try {
|
||||
row = image->getBlackRow(rowNumber, row);
|
||||
} catch (ReaderException re) {
|
||||
} catch (ReaderException const& re) {
|
||||
continue;
|
||||
} catch (IllegalArgumentException re) {
|
||||
} catch (IllegalArgumentException const& re) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* ErrorCorrectionLevel.cpp
|
||||
* zxing
|
||||
*
|
||||
* Created by Christian Brunschen on 15/05/2008.
|
||||
* Copyright 2008 ZXing authors All rights reserved.
|
||||
* Copyright 2008-2011 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.
|
||||
|
@ -20,15 +21,30 @@
|
|||
|
||||
#include <zxing/qrcode/ErrorCorrectionLevel.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace zxing {
|
||||
namespace qrcode {
|
||||
|
||||
ErrorCorrectionLevel::ErrorCorrectionLevel(int inOrdinal) :
|
||||
ordinal_(inOrdinal) {
|
||||
ErrorCorrectionLevel::ErrorCorrectionLevel(int inOrdinal,
|
||||
int bits,
|
||||
char const* name) :
|
||||
ordinal_(inOrdinal), bits_(bits), name_(name) {}
|
||||
|
||||
int ErrorCorrectionLevel::ordinal() const {
|
||||
return ordinal_;
|
||||
}
|
||||
|
||||
int ErrorCorrectionLevel::ordinal() {
|
||||
return ordinal_;
|
||||
int ErrorCorrectionLevel::bits() const {
|
||||
return bits_;
|
||||
}
|
||||
|
||||
string const& ErrorCorrectionLevel::name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
ErrorCorrectionLevel::operator string const& () const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
ErrorCorrectionLevel& ErrorCorrectionLevel::forBits(int bits) {
|
||||
|
@ -38,10 +54,10 @@ ErrorCorrectionLevel& ErrorCorrectionLevel::forBits(int bits) {
|
|||
return *FOR_BITS[bits];
|
||||
}
|
||||
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::L(0);
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::M(1);
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::Q(2);
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::H(3);
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::L(0, 0x01, "L");
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::M(1, 0x00, "M");
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::Q(2, 0x03, "Q");
|
||||
ErrorCorrectionLevel ErrorCorrectionLevel::H(3, 0x02, "H");
|
||||
ErrorCorrectionLevel *ErrorCorrectionLevel::FOR_BITS[] = { &M, &L, &H, &Q };
|
||||
int ErrorCorrectionLevel::N_LEVELS = 4;
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@ namespace qrcode {
|
|||
class ErrorCorrectionLevel {
|
||||
private:
|
||||
int ordinal_;
|
||||
ErrorCorrectionLevel(int inOrdinal);
|
||||
int bits_;
|
||||
std::string name_;
|
||||
ErrorCorrectionLevel(int inOrdinal, int bits, char const* name);
|
||||
static ErrorCorrectionLevel *FOR_BITS[];
|
||||
static int N_LEVELS;
|
||||
public:
|
||||
|
@ -37,7 +39,11 @@ public:
|
|||
static ErrorCorrectionLevel Q;
|
||||
static ErrorCorrectionLevel H;
|
||||
|
||||
int ordinal();
|
||||
int ordinal() const;
|
||||
int bits() const;
|
||||
std::string const& name() const;
|
||||
operator std::string const& () const;
|
||||
|
||||
static ErrorCorrectionLevel& forBits(int bits);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
*/
|
||||
|
||||
#include <zxing/qrcode/decoder/DecodedBitStreamParser.h>
|
||||
#include <zxing/common/CharacterSetECI.h>
|
||||
#include <zxing/FormatException.h>
|
||||
#include <zxing/common/StringUtils.h>
|
||||
#include <iostream>
|
||||
#ifndef NO_ICONV
|
||||
#include <iconv.h>
|
||||
|
@ -38,6 +41,7 @@
|
|||
using namespace std;
|
||||
using namespace zxing;
|
||||
using namespace zxing::qrcode;
|
||||
using namespace zxing::common;
|
||||
|
||||
const char DecodedBitStreamParser::ALPHANUMERIC_CHARS[] =
|
||||
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
||||
|
@ -46,19 +50,29 @@ const char DecodedBitStreamParser::ALPHANUMERIC_CHARS[] =
|
|||
'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'
|
||||
};
|
||||
|
||||
const char *DecodedBitStreamParser::ASCII = "ASCII";
|
||||
const char *DecodedBitStreamParser::ISO88591 = "ISO-8859-1";
|
||||
const char *DecodedBitStreamParser::UTF8 = "UTF-8";
|
||||
const char *DecodedBitStreamParser::SHIFT_JIS = "SHIFT_JIS";
|
||||
const char *DecodedBitStreamParser::EUC_JP = "EUC-JP";
|
||||
namespace {int GB2312_SUBSET = 1;}
|
||||
|
||||
void DecodedBitStreamParser::append(std::string &result, const unsigned char *bufIn, size_t nIn, const char *src) {
|
||||
void DecodedBitStreamParser::append(std::string &result,
|
||||
string const& in,
|
||||
const char *src) {
|
||||
append(result, (unsigned char const*)in.c_str(), in.length(), src);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::append(std::string &result,
|
||||
const unsigned char *bufIn,
|
||||
size_t nIn,
|
||||
const char *src) {
|
||||
#ifndef NO_ICONV
|
||||
if (nIn == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
iconv_t cd = iconv_open(UTF8, src);
|
||||
iconv_t cd = iconv_open(StringUtils::UTF8, src);
|
||||
if (cd == (iconv_t)-1) {
|
||||
result.append((const char *)bufIn, nIn);
|
||||
return;
|
||||
}
|
||||
|
||||
const int maxOut = 4 * nIn + 1;
|
||||
unsigned char* bufOut = new unsigned char[maxOut];
|
||||
|
||||
|
@ -86,6 +100,47 @@ void DecodedBitStreamParser::append(std::string &result, const unsigned char *bu
|
|||
#endif
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeHanziSegment(Ref<BitSource> bits_,
|
||||
string& result,
|
||||
int count) {
|
||||
BitSource& bits (*bits_);
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count * 13 > bits.available()) {
|
||||
throw FormatException();
|
||||
}
|
||||
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as GB2312 afterwards
|
||||
size_t nBytes = 2 * count;
|
||||
unsigned char* buffer = new unsigned char[nBytes];
|
||||
int offset = 0;
|
||||
while (count > 0) {
|
||||
// Each 13 bits encodes a 2-byte character
|
||||
int twoBytes = bits.readBits(13);
|
||||
int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
|
||||
if (assembledTwoBytes < 0x003BF) {
|
||||
// In the 0xA1A1 to 0xAAFE range
|
||||
assembledTwoBytes += 0x0A1A1;
|
||||
} else {
|
||||
// In the 0xB0A1 to 0xFAFE range
|
||||
assembledTwoBytes += 0x0A6A1;
|
||||
}
|
||||
buffer[offset] = (unsigned char) ((assembledTwoBytes >> 8) & 0xFF);
|
||||
buffer[offset + 1] = (unsigned char) (assembledTwoBytes & 0xFF);
|
||||
offset += 2;
|
||||
count--;
|
||||
}
|
||||
|
||||
try {
|
||||
append(result, buffer, nBytes, StringUtils::GB2312);
|
||||
} catch (ReaderException const& re) {
|
||||
delete [] buffer;
|
||||
throw FormatException();
|
||||
}
|
||||
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string &result, int count) {
|
||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
||||
// and decode as Shift_JIS afterwards
|
||||
|
@ -110,30 +165,45 @@ void DecodedBitStreamParser::decodeKanjiSegment(Ref<BitSource> bits, std::string
|
|||
count--;
|
||||
}
|
||||
|
||||
append(result, buffer, nBytes, SHIFT_JIS);
|
||||
append(result, buffer, nBytes, StringUtils::SHIFT_JIS);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits, std::string &result, int count) {
|
||||
void DecodedBitStreamParser::decodeByteSegment(Ref<BitSource> bits_,
|
||||
string& result,
|
||||
int count,
|
||||
CharacterSetECI* currentCharacterSetECI,
|
||||
ArrayRef< ArrayRef<unsigned char> >& byteSegments,
|
||||
Hashtable const& hints) {
|
||||
int nBytes = count;
|
||||
unsigned char* readBytes = new unsigned char[nBytes];
|
||||
if (count << 3 > bits->available()) {
|
||||
ostringstream s;
|
||||
s << "Count too large: " << count;
|
||||
delete[] readBytes;
|
||||
throw ReaderException(s.str().c_str());
|
||||
BitSource& bits (*bits_);
|
||||
// Don't crash trying to read more bits than we have available.
|
||||
if (count << 3 > bits.available()) {
|
||||
throw FormatException();
|
||||
}
|
||||
|
||||
ArrayRef<unsigned char> bytes_ (count);
|
||||
unsigned char* readBytes = &(*bytes_)[0];
|
||||
for (int i = 0; i < count; i++) {
|
||||
readBytes[i] = (unsigned char)bits->readBits(8);
|
||||
readBytes[i] = (unsigned char) bits.readBits(8);
|
||||
}
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
const char *encoding = guessEncoding(readBytes, nBytes);
|
||||
append(result, readBytes, nBytes, encoding);
|
||||
delete[] readBytes;
|
||||
string encoding;
|
||||
if (currentCharacterSetECI == 0) {
|
||||
// The spec isn't clear on this mode; see
|
||||
// section 6.4.5: t does not say which encoding to assuming
|
||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||
// Shift_JIS -- without anything like an ECI designator to
|
||||
// give a hint.
|
||||
encoding = StringUtils::guessEncoding(readBytes, count, hints);
|
||||
} else {
|
||||
encoding = currentCharacterSetECI->getEncodingName();
|
||||
}
|
||||
try {
|
||||
append(result, readBytes, nBytes, encoding.c_str());
|
||||
} catch (ReaderException const& re) {
|
||||
throw FormatException();
|
||||
}
|
||||
byteSegments->values().push_back(bytes_);
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count) {
|
||||
|
@ -186,249 +256,147 @@ void DecodedBitStreamParser::decodeNumericSegment(Ref<BitSource> bits, std::stri
|
|||
}
|
||||
bytes[i++] = ALPHANUMERIC_CHARS[digitBits];
|
||||
}
|
||||
append(result, bytes, nBytes, ASCII);
|
||||
append(result, bytes, nBytes, StringUtils::ASCII);
|
||||
delete[] bytes;
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeAlphanumericSegment(Ref<BitSource> bits, std::string &result, int count) {
|
||||
int nBytes = count;
|
||||
unsigned char* bytes = new unsigned char[nBytes];
|
||||
int i = 0;
|
||||
char DecodedBitStreamParser::toAlphaNumericChar(size_t value) {
|
||||
if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) {
|
||||
throw FormatException();
|
||||
}
|
||||
return ALPHANUMERIC_CHARS[value];
|
||||
}
|
||||
|
||||
void DecodedBitStreamParser::decodeAlphanumericSegment(Ref<BitSource> bits_,
|
||||
string& result,
|
||||
int count,
|
||||
bool fc1InEffect) {
|
||||
BitSource& bits (*bits_);
|
||||
ostringstream bytes;
|
||||
// Read two characters at a time
|
||||
while (count > 1) {
|
||||
int nextTwoCharsBits = bits->readBits(11);
|
||||
bytes[i++] = ALPHANUMERIC_CHARS[nextTwoCharsBits / 45];
|
||||
bytes[i++] = ALPHANUMERIC_CHARS[nextTwoCharsBits % 45];
|
||||
int nextTwoCharsBits = bits.readBits(11);
|
||||
bytes << toAlphaNumericChar(nextTwoCharsBits / 45);
|
||||
bytes << toAlphaNumericChar(nextTwoCharsBits % 45);
|
||||
count -= 2;
|
||||
}
|
||||
if (count == 1) {
|
||||
bytes[i++] = ALPHANUMERIC_CHARS[bits->readBits(6)];
|
||||
// special case: one character left
|
||||
bytes << toAlphaNumericChar(bits.readBits(6));
|
||||
}
|
||||
append(result, bytes, nBytes, ASCII);
|
||||
delete[] bytes;
|
||||
}
|
||||
|
||||
const char *
|
||||
DecodedBitStreamParser::guessEncoding(unsigned char *bytes, int length) {
|
||||
const bool ASSUME_SHIFT_JIS = false;
|
||||
char const* const PLATFORM_DEFAULT_ENCODING="UTF-8";
|
||||
|
||||
// Does it start with the UTF-8 byte order mark? then guess it's UTF-8
|
||||
if (length > 3 && bytes[0] == (unsigned char)0xEF && bytes[1] == (unsigned char)0xBB && bytes[2]
|
||||
== (unsigned char)0xBF) {
|
||||
return UTF8;
|
||||
}
|
||||
// For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
|
||||
// which should be by far the most common encodings. ISO-8859-1
|
||||
// should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
|
||||
// uses this as a first byte of a two-byte character. If we see this
|
||||
// followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
|
||||
// If we see something else in that second byte, we'll make the risky guess
|
||||
// that it's UTF-8.
|
||||
bool canBeISO88591 = true;
|
||||
bool canBeShiftJIS = true;
|
||||
bool canBeUTF8 = true;
|
||||
int utf8BytesLeft = 0;
|
||||
int maybeDoubleByteCount = 0;
|
||||
int maybeSingleByteKatakanaCount = 0;
|
||||
bool sawLatin1Supplement = false;
|
||||
bool sawUTF8Start = false;
|
||||
bool lastWasPossibleDoubleByteStart = false;
|
||||
for (int i = 0;
|
||||
i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8);
|
||||
i++) {
|
||||
int value = bytes[i] & 0xFF;
|
||||
|
||||
// UTF-8 stuff
|
||||
if (value >= 0x80 && value <= 0xBF) {
|
||||
if (utf8BytesLeft > 0) {
|
||||
utf8BytesLeft--;
|
||||
}
|
||||
} else {
|
||||
if (utf8BytesLeft > 0) {
|
||||
canBeUTF8 = false;
|
||||
}
|
||||
if (value >= 0xC0 && value <= 0xFD) {
|
||||
sawUTF8Start = true;
|
||||
int valueCopy = value;
|
||||
while ((valueCopy & 0x40) != 0) {
|
||||
utf8BytesLeft++;
|
||||
valueCopy <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shift_JIS stuff
|
||||
|
||||
if (value >= 0xA1 && value <= 0xDF) {
|
||||
// count the number of characters that might be a Shift_JIS single-byte Katakana character
|
||||
if (!lastWasPossibleDoubleByteStart) {
|
||||
maybeSingleByteKatakanaCount++;
|
||||
}
|
||||
}
|
||||
if (!lastWasPossibleDoubleByteStart &&
|
||||
((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) {
|
||||
canBeShiftJIS = false;
|
||||
}
|
||||
if (((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF))) {
|
||||
// These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid
|
||||
// second byte.
|
||||
if (lastWasPossibleDoubleByteStart) {
|
||||
// If we just checked this and the last byte for being a valid double-byte
|
||||
// char, don't check starting on this byte. If this and the last byte
|
||||
// formed a valid pair, then this shouldn't be checked to see if it starts
|
||||
// a double byte pair of course.
|
||||
lastWasPossibleDoubleByteStart = false;
|
||||
// See section 6.4.8.1, 6.4.8.2
|
||||
string s = bytes.str();
|
||||
if (fc1InEffect) {
|
||||
// We need to massage the result a bit if in an FNC1 mode:
|
||||
ostringstream r;
|
||||
for (size_t i = 0; i < s.length(); i++) {
|
||||
if (s[i] != '%') {
|
||||
r << s[i];
|
||||
} else {
|
||||
// ... otherwise do check to see if this plus the next byte form a valid
|
||||
// double byte pair encoding a character.
|
||||
lastWasPossibleDoubleByteStart = true;
|
||||
if (i >= length - 1) {
|
||||
canBeShiftJIS = false;
|
||||
if (i < s.length() - 1 && s[i + 1] == '%') {
|
||||
// %% is rendered as %
|
||||
r << s[i++];
|
||||
} else {
|
||||
int nextValue = bytes[i + 1] & 0xFF;
|
||||
if (nextValue < 0x40 || nextValue > 0xFC) {
|
||||
canBeShiftJIS = false;
|
||||
} else {
|
||||
maybeDoubleByteCount++;
|
||||
}
|
||||
// There is some conflicting information out there about which bytes can follow which in
|
||||
// double-byte Shift_JIS characters. The rule above seems to be the one that matches practice.
|
||||
// In alpha mode, % should be converted to FNC1 separator 0x1D
|
||||
r << (char)0x1D;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastWasPossibleDoubleByteStart = false;
|
||||
}
|
||||
s = r.str();
|
||||
}
|
||||
if (utf8BytesLeft > 0) {
|
||||
canBeUTF8 = false;
|
||||
}
|
||||
|
||||
// Easy -- if assuming Shift_JIS and no evidence it can't be, done
|
||||
if (canBeShiftJIS && ASSUME_SHIFT_JIS) {
|
||||
return SHIFT_JIS;
|
||||
}
|
||||
if (canBeUTF8 && sawUTF8Start) {
|
||||
return UTF8;
|
||||
}
|
||||
// Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is:
|
||||
// - If we saw
|
||||
// - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or
|
||||
// - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1),
|
||||
// - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS
|
||||
if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) {
|
||||
return SHIFT_JIS;
|
||||
}
|
||||
// Otherwise, we default to ISO-8859-1 unless we know it can't be
|
||||
if (!sawLatin1Supplement && canBeISO88591) {
|
||||
return ISO88591;
|
||||
}
|
||||
// Otherwise, we take a wild guess with platform encoding
|
||||
return PLATFORM_DEFAULT_ENCODING;
|
||||
append(result, s, StringUtils::ASCII);
|
||||
}
|
||||
|
||||
/*
|
||||
string DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes, Version *version) {
|
||||
namespace {
|
||||
int parseECIValue(BitSource bits) {
|
||||
int firstByte = bits.readBits(8);
|
||||
if ((firstByte & 0x80) == 0) {
|
||||
// just one byte
|
||||
return firstByte & 0x7F;
|
||||
}
|
||||
if ((firstByte & 0xC0) == 0x80) {
|
||||
// two bytes
|
||||
int secondByte = bits.readBits(8);
|
||||
return ((firstByte & 0x3F) << 8) | secondByte;
|
||||
}
|
||||
if ((firstByte & 0xE0) == 0xC0) {
|
||||
// three bytes
|
||||
int secondThirdBytes = bits.readBits(16);
|
||||
return ((firstByte & 0x1F) << 16) | secondThirdBytes;
|
||||
}
|
||||
throw IllegalArgumentException("Bad ECI bits starting with byte " + firstByte);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<DecoderResult>
|
||||
DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes,
|
||||
Version* version,
|
||||
ErrorCorrectionLevel const& ecLevel,
|
||||
Hashtable const& hints) {
|
||||
Ref<BitSource> bits_ (new BitSource(bytes));
|
||||
BitSource& bits (*bits_);
|
||||
string result;
|
||||
Ref<BitSource> bits(new BitSource(bytes));
|
||||
Mode *mode = &Mode::TERMINATOR;
|
||||
do {
|
||||
// While still another segment to read...
|
||||
if (bits->available() < 4) {
|
||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
||||
mode = &Mode::TERMINATOR;
|
||||
} else {
|
||||
mode = &Mode::forBits(bits->readBits(4)); // mode is encoded by 4 bits
|
||||
}
|
||||
if (mode != &Mode::TERMINATOR) {
|
||||
// How many characters will follow, encoded in this mode?
|
||||
int count = bits->readBits(mode->getCharacterCountBits(version));
|
||||
if (mode == &Mode::NUMERIC) {
|
||||
decodeNumericSegment(bits, result, count);
|
||||
} else if (mode == &Mode::ALPHANUMERIC) {
|
||||
decodeAlphanumericSegment(bits, result, count);
|
||||
} else if (mode == &Mode::BYTE) {
|
||||
decodeByteSegment(bits, result, count);
|
||||
} else if (mode == &Mode::KANJI) {
|
||||
decodeKanjiSegment(bits, result, count);
|
||||
} else {
|
||||
throw ReaderException("Unsupported mode indicator");
|
||||
}
|
||||
}
|
||||
} while (mode != &Mode::TERMINATOR);
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
DecoderResult DecodedBitStreamParser::decode(ArrayRef<unsigned char> bytes,
|
||||
Version* version,
|
||||
ErrorCorrectionLevel ecLevel,
|
||||
Hashtable hints) {
|
||||
BitSource bits = new BitSource(bytes);
|
||||
StringBuffer result = new StringBuffer(50);
|
||||
CharacterSetECI currentCharacterSetECI = null;
|
||||
boolean fc1InEffect = false;
|
||||
Vector byteSegments = new Vector(1);
|
||||
Mode mode;
|
||||
CharacterSetECI* currentCharacterSetECI = 0;
|
||||
bool fc1InEffect = false;
|
||||
ArrayRef< ArrayRef<unsigned char> > byteSegments (size_t(0));
|
||||
Mode* mode = 0;
|
||||
do {
|
||||
// While still another segment to read...
|
||||
if (bits.available() < 4) {
|
||||
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
||||
mode = Mode.TERMINATOR;
|
||||
mode = &Mode::TERMINATOR;
|
||||
} else {
|
||||
try {
|
||||
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw FormatException.getFormatInstance();
|
||||
mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits
|
||||
} catch (IllegalArgumentException const& iae) {
|
||||
throw iae;
|
||||
// throw FormatException.getFormatInstance();
|
||||
}
|
||||
}
|
||||
if (!mode.equals(Mode.TERMINATOR)) {
|
||||
if (mode.equals(Mode.FNC1_FIRST_POSITION) || mode.equals(Mode.FNC1_SECOND_POSITION)) {
|
||||
if (mode != &Mode::TERMINATOR) {
|
||||
if ((mode == &Mode::FNC1_FIRST_POSITION) || (mode == &Mode::FNC1_SECOND_POSITION)) {
|
||||
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
||||
fc1InEffect = true;
|
||||
} else if (mode.equals(Mode.STRUCTURED_APPEND)) {
|
||||
} else if (mode == &Mode::STRUCTURED_APPEND) {
|
||||
// not really supported; all we do is ignore it
|
||||
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
||||
bits.readBits(16);
|
||||
} else if (mode.equals(Mode.ECI)) {
|
||||
} else if (mode == &Mode::ECI) {
|
||||
// Count doesn't apply to ECI
|
||||
int value = parseECIValue(bits);
|
||||
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (currentCharacterSetECI == null) {
|
||||
throw FormatException.getFormatInstance();
|
||||
currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value);
|
||||
if (currentCharacterSetECI == 0) {
|
||||
throw FormatException();
|
||||
}
|
||||
} else {
|
||||
// First handle Hanzi mode which does not start with character count
|
||||
if (mode.equals(Mode.HANZI)) {
|
||||
if (mode == &Mode::HANZI) {
|
||||
//chinese mode contains a sub set indicator right after mode indicator
|
||||
int subset = bits.readBits(4);
|
||||
int countHanzi = bits.readBits(mode.getCharacterCountBits(version));
|
||||
int countHanzi = bits.readBits(mode->getCharacterCountBits(version));
|
||||
if (subset == GB2312_SUBSET) {
|
||||
decodeHanziSegment(bits, result, countHanzi);
|
||||
decodeHanziSegment(bits_, result, countHanzi);
|
||||
}
|
||||
} else {
|
||||
// "Normal" QR code modes:
|
||||
// How many characters will follow, encoded in this mode?
|
||||
int count = bits.readBits(mode.getCharacterCountBits(version));
|
||||
if (mode.equals(Mode.NUMERIC)) {
|
||||
decodeNumericSegment(bits, result, count);
|
||||
} else if (mode.equals(Mode.ALPHANUMERIC)) {
|
||||
decodeAlphanumericSegment(bits, result, count, fc1InEffect);
|
||||
} else if (mode.equals(Mode.BYTE)) {
|
||||
decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints);
|
||||
} else if (mode.equals(Mode.KANJI)) {
|
||||
decodeKanjiSegment(bits, result, count);
|
||||
int count = bits.readBits(mode->getCharacterCountBits(version));
|
||||
if (mode == &Mode::NUMERIC) {
|
||||
decodeNumericSegment(bits_, result, count);
|
||||
} else if (mode == &Mode::ALPHANUMERIC) {
|
||||
decodeAlphanumericSegment(bits_, result, count, fc1InEffect);
|
||||
} else if (mode == &Mode::BYTE) {
|
||||
decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints);
|
||||
} else if (mode == &Mode::KANJI) {
|
||||
decodeKanjiSegment(bits_, result, count);
|
||||
} else {
|
||||
throw FormatException.getFormatInstance();
|
||||
throw FormatException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!mode.equals(Mode.TERMINATOR));
|
||||
} while (mode != &Mode::TERMINATOR);
|
||||
|
||||
return new DecoderResult(bytes,
|
||||
result.toString(),
|
||||
byteSegments.isEmpty() ? null : byteSegments,
|
||||
ecLevel == null ? null : ecLevel.toString());
|
||||
return Ref<DecoderResult>(new DecoderResult(bytes, Ref<String>(new String(result)), byteSegments, (string)ecLevel));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,33 +24,46 @@
|
|||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <zxing/qrcode/decoder/Mode.h>
|
||||
#include <zxing/common/BitSource.h>
|
||||
#include <zxing/common/Counted.h>
|
||||
#include <zxing/common/Array.h>
|
||||
#include <zxing/common/DecoderResult.h>
|
||||
#include <zxing/common/CharacterSetECI.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace qrcode {
|
||||
|
||||
class DecodedBitStreamParser {
|
||||
public:
|
||||
typedef std::map<DecodeHintType, std::string> Hashtable;
|
||||
|
||||
private:
|
||||
static const char ALPHANUMERIC_CHARS[];
|
||||
|
||||
static const char *ASCII;
|
||||
static const char *ISO88591;
|
||||
static const char *UTF8;
|
||||
static const char *SHIFT_JIS;
|
||||
static const char *EUC_JP;
|
||||
static char const ALPHANUMERIC_CHARS[];
|
||||
static char toAlphaNumericChar(size_t value);
|
||||
|
||||
static void decodeHanziSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeKanjiSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeByteSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeAlphanumericSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static void decodeByteSegment(Ref<BitSource> bits_,
|
||||
std::string& result,
|
||||
int count,
|
||||
zxing::common::CharacterSetECI* currentCharacterSetECI,
|
||||
ArrayRef< ArrayRef<unsigned char> >& byteSegments,
|
||||
Hashtable const& hints);
|
||||
static void decodeAlphanumericSegment(Ref<BitSource> bits, std::string &result, int count, bool fc1InEffect);
|
||||
static void decodeNumericSegment(Ref<BitSource> bits, std::string &result, int count);
|
||||
static const char *guessEncoding(unsigned char *bytes, int length);
|
||||
|
||||
static void append(std::string &ost, const unsigned char *bufIn, size_t nIn, const char *src);
|
||||
static void append(std::string &ost, std::string const& in, const char *src);
|
||||
|
||||
public:
|
||||
static DecoderResulta decode(ArrayRef<unsigned char> bytes, Version *version);
|
||||
static Ref<DecoderResult> decode(ArrayRef<unsigned char> bytes,
|
||||
Version *version,
|
||||
ErrorCorrectionLevel const& ecLevel,
|
||||
Hashtable const& hints);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ void Decoder::correctErrors(ArrayRef<unsigned char> codewordBytes, int numDataCo
|
|||
|
||||
try {
|
||||
rsDecoder_.decode(codewordInts, numECCodewords);
|
||||
} catch (ReedSolomonException ex) {
|
||||
} catch (ReedSolomonException const& ex) {
|
||||
ReaderException rex(ex.what());
|
||||
throw rex;
|
||||
}
|
||||
|
@ -92,11 +92,10 @@ Ref<DecoderResult> Decoder::decode(Ref<BitMatrix> bits) {
|
|||
}
|
||||
}
|
||||
|
||||
// Decode the contents of that stream of bytes
|
||||
Ref<String> text(new String(DecodedBitStreamParser::decode(resultBytes, version)));
|
||||
|
||||
Ref<DecoderResult> result(new DecoderResult(resultBytes, text));
|
||||
return result;
|
||||
return DecodedBitStreamParser::decode(resultBytes,
|
||||
version,
|
||||
ecLevel,
|
||||
DecodedBitStreamParser::Hashtable());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,22 +45,33 @@ Mode::Mode(int cbv0_9, int cbv10_26, int cbv27, int bits, char const* name) :
|
|||
}
|
||||
|
||||
Mode& Mode::forBits(int bits) {
|
||||
switch (bits) {
|
||||
case 0x0:
|
||||
return TERMINATOR;
|
||||
case 0x1:
|
||||
return NUMERIC;
|
||||
case 0x2:
|
||||
return ALPHANUMERIC;
|
||||
case 0x4:
|
||||
return BYTE;
|
||||
case 0x8:
|
||||
return KANJI;
|
||||
default:
|
||||
ostringstream s;
|
||||
s << "Illegal mode bits: " << bits;
|
||||
throw ReaderException(s.str().c_str());
|
||||
}
|
||||
switch (bits) {
|
||||
case 0x0:
|
||||
return TERMINATOR;
|
||||
case 0x1:
|
||||
return NUMERIC;
|
||||
case 0x2:
|
||||
return ALPHANUMERIC;
|
||||
case 0x3:
|
||||
return STRUCTURED_APPEND;
|
||||
case 0x4:
|
||||
return BYTE;
|
||||
case 0x5:
|
||||
return FNC1_FIRST_POSITION;
|
||||
case 0x7:
|
||||
return ECI;
|
||||
case 0x8:
|
||||
return KANJI;
|
||||
case 0x9:
|
||||
return FNC1_SECOND_POSITION;
|
||||
case 0xD:
|
||||
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
|
||||
return HANZI;
|
||||
default:
|
||||
ostringstream s;
|
||||
s << "Illegal mode bits: " << bits;
|
||||
throw ReaderException(s.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int Mode::getCharacterCountBits(Version *version) {
|
||||
|
|
|
@ -82,7 +82,7 @@ Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
|
|||
try {
|
||||
alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i);
|
||||
break;
|
||||
} catch (zxing::ReaderException re) {
|
||||
} catch (zxing::ReaderException const& re) {
|
||||
// try next round
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* main.cpp
|
||||
* zxing
|
||||
|
|
Loading…
Reference in a new issue