diff --git a/examples/QQrDecoder/QCameraControllerWidget.cpp b/examples/QQrDecoder/QCameraControllerWidget.cpp index 62d3c58..7365db7 100644 --- a/examples/QQrDecoder/QCameraControllerWidget.cpp +++ b/examples/QQrDecoder/QCameraControllerWidget.cpp @@ -41,7 +41,9 @@ #include "QCameraControllerWidget.h" //#include #include - +#include +#include +#include /***************************************************************************** * QCameraControllerWidget @@ -125,11 +127,17 @@ QCameraControllerWidget::QCameraControllerWidget(QWidget *parent) : setLayout(hboxl); + QStringList list = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); + if(list.isEmpty()) + imagePath = qApp->applicationDirPath(); + else + imagePath = list.at(0); + fileWatcher = new QFileSystemWatcher(); - fileWatcher->addPath(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + fileWatcher->addPath(imagePath); connect(fileWatcher, SIGNAL( directoryChanged (const QString &)), this, SLOT(deleteImage(const QString &))); - imageFolder = QDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); + imageFolder = QDir(imagePath); QStringList filters; filters << "camera*"; imageFolder.setNameFilters(filters); @@ -280,6 +288,7 @@ void QCameraControllerWidget::captureImage() void QCameraControllerWidget::onImageCaptured(int id, const QImage &preview) { + Q_UNUSED(id); // m_stillImageCapture->cancelCapture(); // showViewFinder = false; m_focusing = false; @@ -291,6 +300,7 @@ void QCameraControllerWidget::onImageCaptured(int id, const QImage &preview) void QCameraControllerWidget::deleteImage(const QString & folderPath) { + Q_UNUSED(folderPath); //qdebug() << "Detected change to folder: " << folderPath; QStringList files = imageFolder.entryList(imageFolder.nameFilters()); @@ -300,8 +310,7 @@ void QCameraControllerWidget::deleteImage(const QString & folderPath) //qdebug() << "Checking file: " << image; if(image.startsWith("camera")) { - QString path(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); - QDir pathDir(path); + QDir pathDir(imagePath); pathDir.remove(image); //qdebug() << "file deleted: " << image; @@ -354,6 +363,7 @@ void QCameraControllerWidget::updateVideo() void QCameraControllerWidget::paintEvent(QPaintEvent *event) { + Q_UNUSED(event); //QMainWindow::paintEvent(event); QPainter painter(this); diff --git a/examples/QQrDecoder/QCameraControllerWidget.h b/examples/QQrDecoder/QCameraControllerWidget.h index fe074f9..5ae11b9 100644 --- a/examples/QQrDecoder/QCameraControllerWidget.h +++ b/examples/QQrDecoder/QCameraControllerWidget.h @@ -58,7 +58,7 @@ #include "myvideosurface.h" #include "button.h" - +#include class QCameraControllerWidget: public QWidget, public VideoIF { @@ -117,6 +117,7 @@ private: QCameraFocus* cameraFocus; QFileSystemWatcher* fileWatcher; QDir imageFolder; + QString imagePath; }; #endif // QCAMERA_H diff --git a/examples/QQrDecoder/QQrDecoder.h b/examples/QQrDecoder/QQrDecoder.h index d56ecc4..5c1359c 100644 --- a/examples/QQrDecoder/QQrDecoder.h +++ b/examples/QQrDecoder/QQrDecoder.h @@ -31,7 +31,7 @@ #ifndef QQRDECODER_H #define QQRDECODER_H -#include +#include #include #include "ui_QQrDecoder.h" #include diff --git a/examples/QQrDecoder/QQrDecoder.pro b/examples/QQrDecoder/QQrDecoder.pro index 6a1c83d..ca021dd 100644 --- a/examples/QQrDecoder/QQrDecoder.pro +++ b/examples/QQrDecoder/QQrDecoder.pro @@ -1,15 +1,9 @@ TEMPLATE = app TARGET = QQrDecoder -QT += core \ - gui \ - declarative +QT += core gui multimedia widgets VERSION = 2.0.0 -CONFIG += mobility -MOBILITY = multimedia #\ - #systeminfo - RESOURCES += resources.qrc include(../../source/QZXing.pri) diff --git a/examples/QQrDecoder/button.cpp b/examples/QQrDecoder/button.cpp index 6b7ea3a..8ba3aaf 100644 --- a/examples/QQrDecoder/button.cpp +++ b/examples/QQrDecoder/button.cpp @@ -46,7 +46,6 @@ Button::Button(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f) { - m_downPixmap = 0; m_disabled = false; m_toggled = false; m_toggle_enabled = false; diff --git a/source/CameraImageWrapper.cpp b/source/CameraImageWrapper.cpp index dbce804..7a1148d 100644 --- a/source/CameraImageWrapper.cpp +++ b/source/CameraImageWrapper.cpp @@ -114,7 +114,7 @@ ArrayRef CameraImageWrapper::getMatrix() const ArrayRef tmpRow; tmpRow = getRow(y, ArrayRef(width)); #if __cplusplus > 199711L - memcpy(m, tmpRow->values()..data(), width); + memcpy(m, tmpRow->values().data(), width); #else memcpy(m, &tmpRow->values()[0], width); #endif diff --git a/source/QZXing.h b/source/QZXing.h index 61201bd..131502d 100644 --- a/source/QZXing.h +++ b/source/QZXing.h @@ -28,9 +28,9 @@ class ImageHandler; */ class #ifndef DISABLE_LIBRARY_FEATURES - QZXINGSHARED_EXPORT + QZXINGSHARED_EXPORT #endif - QZXing : public QObject{ + QZXing : public QObject { Q_OBJECT Q_ENUMS(DecoderFormat) @@ -75,6 +75,10 @@ public: } #endif + QString decoderFormatToString(int fmt); + QString foundedFormat() const; + QString charSet() const; + public slots: /** * The decoding function. Will try to decode the given image based on the enabled decoders. @@ -85,14 +89,13 @@ public slots: * The smoothTransformation flag determines whether the transformation will be smooth or fast. * Smooth transformation provides better results but fast transformation is...faster. */ - QString decodeImage(QImage &image, int maxWidth=-1, int maxHeight=-1, bool smoothTransformation = false); + QString decodeImage(QImage &image, int maxWidth = -1, int maxHeight = -1, bool smoothTransformation = false); /** * The decoding function. Will try to decode the given image based on the enabled decoders. * The input image is read from a local image file. */ QString decodeImageFromFile(const QString& imageFilePath, int maxWidth=-1, int maxHeight=-1, bool smoothTransformation = false); - /** * The decoding function accessible from QML. (Suggested for Qt 4.x) */ @@ -102,7 +105,7 @@ public slots: * The decoding function accessible from QML. Able to set the decoding * of a portion of the image. (Suggested for Qt 4.x) */ - QString decodeSubImageQML(QObject* item, + QString decodeSubImageQML(QObject *item, const double offsetX = 0 , const double offsetY = 0, const double width = 0, const double height = 0); @@ -123,6 +126,7 @@ public slots: QString decodeSubImageQML(const QUrl &imageUrl, const double offsetX = 0, const double offsetY = 0, const double width = 0, const double height = 0); + /** * Get the prossecing time in millisecond of the last decode operation. * Added mainly as a statistic measure. @@ -140,19 +144,23 @@ public slots: * As argument it is possible to pass conjuction of decoders by using logic OR. * e.x. setDecoder ( DecoderFormat_QR_CODE | DecoderFormat_EAN_13 | DecoderFormat_CODE_39 ) */ - void setDecoder(const uint& hint); + void setDecoder(const uint &hint); signals: void decodingStarted(); void decodingFinished(bool succeeded); void tagFound(QString tag); void enabledFormatsChanged(); + void tagFoundAdvanced(QString tag, QString format, QString charSet); + void error(QString msg); private: - zxing::MultiFormatReader* decoder; + zxing::MultiFormatReader *decoder; DecoderFormatType enabledDecoders; - ImageHandler* imageHandler; + ImageHandler *imageHandler; int processingTime; + QString foundedFmt; + QString charSet_; /** * If true, the decoding operation will take place at a different thread. diff --git a/source/QZXing.pri b/source/QZXing.pri index 04e077e..f14a082 100644 --- a/source/QZXing.pri +++ b/source/QZXing.pri @@ -1,7 +1,7 @@ QT += core gui -greaterThan(QT_VERSION, 4.7): QT += declarative -greaterThan(QT_VERSION, 5.0): QT += quick +greaterThan(QT_VERSION, 4.7): lessThan(QT_VERSION, 5.0): QT += declarative +greaterThan(QT_MAJOR_VERSION, 4): QT += quick DEFINES += QZXING_LIBRARY \ ZXING_ICONV_CONST \ @@ -284,3 +284,7 @@ win32-g++{ SOURCES += $$PWD/zxing/win32/zxing/win_iconv.c } + +!win32{ + DEFINES += NO_ICONV +} diff --git a/source/imagehandler.cpp b/source/imagehandler.cpp index 6b5976f..c939aaf 100644 --- a/source/imagehandler.cpp +++ b/source/imagehandler.cpp @@ -16,7 +16,7 @@ QImage ImageHandler::extractQImage(QObject *imageObj, { QGraphicsObject *item = qobject_cast(imageObj); - if (!item ) { + if (!item) { qDebug() << "Item is NULL"; return QImage(); } diff --git a/source/qzxing.cpp b/source/qzxing.cpp index 456fcca..8fba26f 100644 --- a/source/qzxing.cpp +++ b/source/qzxing.cpp @@ -45,6 +45,73 @@ QZXing::QZXing(QZXing::DecoderFormat decodeHints, QObject *parent) : QObject(par setDecoder(decodeHints); } +QString QZXing::decoderFormatToString(int fmt) +{ + switch (fmt) { + case 1: + return "AZTEC"; + + case 2: + return "CODABAR"; + + case 3: + return "CODE_39"; + + case 4: + return "CODE_93"; + + case 5: + return "CODE_128"; + + case 6: + return "DATA_MATRIX"; + + case 7: + return "EAN_8"; + + case 8: + return "EAN_13"; + + case 9: + return "ITF"; + + case 10: + return "MAXICODE"; + + case 11: + return "PDF_417"; + + case 12: + return "QR_CODE"; + + case 13: + return "RSS_14"; + + case 14: + return "RSS_EXPANDED"; + + case 15: + return "UPC_A"; + + case 16: + return "UPC_E"; + + case 17: + return "UPC_EAN_EXTENSION"; + } // switch + return QString(); +} + +QString QZXing::foundedFormat() const +{ + return foundedFmt; +} + +QString QZXing::charSet() const +{ + return charSet_; +} + void QZXing::setDecoder(const uint &hint) { unsigned int newHints = 0; @@ -114,50 +181,58 @@ QString QZXing::decodeImage(QImage &image, int maxWidth, int maxHeight, bool smo if(image.isNull()) { - qDebug() << "Image Null"; emit decodingFinished(false); - processingTime = -1; + processingTime = t.elapsed(); return ""; } - CameraImageWrapper* ciw; - - try{ - if(maxWidth > 0 || maxHeight > 0) + CameraImageWrapper *ciw = NULL; + try { + if ((maxWidth > 0) || (maxHeight > 0)) ciw = CameraImageWrapper::Factory(image, maxWidth, maxHeight, smoothTransformation); else ciw = new CameraImageWrapper(image); Ref imageRef(ciw); - GlobalHistogramBinarizer* binz = new GlobalHistogramBinarizer(imageRef); + GlobalHistogramBinarizer *binz = new GlobalHistogramBinarizer(imageRef); - Ref bz (binz); - BinaryBitmap* bb = new BinaryBitmap(bz); + Ref bz(binz); + BinaryBitmap *bb = new BinaryBitmap(bz); Ref ref(bb); res = decoder->decode(ref, DecodeHints((int)enabledDecoders)); QString string = QString(res->getText()->getText().c_str()); + if (!string.isEmpty() && (string.length() > 0)) { + int fmt = res->getBarcodeFormat().value; + foundedFmt = decoderFormatToString(fmt); + charSet_ = QString::fromStdString(res->getCharSet()); + if (!charSet_.isEmpty()) { + QTextCodec *codec = QTextCodec::codecForName(res->getCharSet().c_str()); + if (codec) + string = codec->toUnicode(res->getText()->getText().c_str()); + } + emit tagFound(string); + emit tagFoundAdvanced(string, foundedFmt, charSet_); + } processingTime = t.elapsed(); - qDebug() << "Deconding succeeded: " << string; - emit tagFound(string); emit decodingFinished(true); return string; } - catch(zxing::Exception& /*e*/) + catch(zxing::Exception &e) { - qDebug() << "Deconding failed"; + emit error(QString(e.what())); emit decodingFinished(false); - processingTime = -1; + processingTime = t.elapsed(); return ""; } } QString QZXing::decodeImageFromFile(const QString& imageFilePath, int maxWidth, int maxHeight, bool smoothTransformation) { - //used to have a check if this image exists - //but was removed because if the image file path doesn't point to a valid image + // used to have a check if this image exists + // but was removed because if the image file path doesn't point to a valid image // then the QImage::isNull will return true and the decoding will fail eitherway. QUrl imageUrl(imageFilePath); QImage tmpImage = QImage(imageUrl.toLocalFile()); @@ -169,12 +244,13 @@ QString QZXing::decodeImageQML(QObject *item) return decodeSubImageQML(item); } -QString QZXing::decodeSubImageQML(QObject* item, +QString QZXing::decodeSubImageQML(QObject *item, const double offsetX, const double offsetY, const double width, const double height) { if(item == NULL) { + processingTime = 0; emit decodingFinished(false); return ""; } @@ -188,6 +264,7 @@ QString QZXing::decodeImageQML(const QUrl &imageUrl) { return decodeSubImageQML(imageUrl); } + QString QZXing::decodeSubImageQML(const QUrl &imageUrl, const double offsetX, const double offsetY, const double width, const double height) @@ -216,7 +293,3 @@ uint QZXing::getEnabledFormats() const { return enabledDecoders; } - - - - diff --git a/source/zxing/zxing/Result.cpp b/source/zxing/zxing/Result.cpp index 17d8700..f99f648 100644 --- a/source/zxing/zxing/Result.cpp +++ b/source/zxing/zxing/Result.cpp @@ -33,8 +33,8 @@ using zxing::BarcodeFormat; Result::Result(Ref text, ArrayRef rawBytes, ArrayRef< Ref > resultPoints, - BarcodeFormat format) : - text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) { + BarcodeFormat format, std::string charSet) : + text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format), charSet_(charSet) { } Result::~Result() { @@ -57,5 +57,10 @@ ArrayRef< Ref >& Result::getResultPoints() { } zxing::BarcodeFormat Result::getBarcodeFormat() const { - return format_; + return format_; +} + +std::string Result::getCharSet() const +{ + return charSet_; } diff --git a/source/zxing/zxing/Result.h b/source/zxing/zxing/Result.h index 1a5da7b..29c5a93 100644 --- a/source/zxing/zxing/Result.h +++ b/source/zxing/zxing/Result.h @@ -35,18 +35,21 @@ private: ArrayRef rawBytes_; ArrayRef< Ref > resultPoints_; BarcodeFormat format_; + //NOTE: My + std::string charSet_; public: Result(Ref text, ArrayRef rawBytes, ArrayRef< Ref > resultPoints, - BarcodeFormat format); + BarcodeFormat format, std::string charSet = ""); ~Result(); Ref getText(); ArrayRef getRawBytes(); ArrayRef< Ref > const& getResultPoints() const; ArrayRef< Ref >& getResultPoints(); BarcodeFormat getBarcodeFormat() const; + std::string getCharSet() const; friend std::ostream& operator<<(std::ostream &out, Result& result); }; diff --git a/source/zxing/zxing/common/DecoderResult.cpp b/source/zxing/zxing/common/DecoderResult.cpp index 923f9e5..5a895a2 100644 --- a/source/zxing/zxing/common/DecoderResult.cpp +++ b/source/zxing/zxing/common/DecoderResult.cpp @@ -27,20 +27,25 @@ using namespace zxing; DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text, ArrayRef< ArrayRef >& byteSegments, - string const& ecLevel) : + string const& ecLevel, string charSet) : rawBytes_(rawBytes), text_(text), byteSegments_(byteSegments), - ecLevel_(ecLevel) {} + ecLevel_(ecLevel), charSet_(charSet) {} DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text) - : rawBytes_(rawBytes), text_(text) {} + : rawBytes_(rawBytes), text_(text),charSet_("") {} ArrayRef DecoderResult::getRawBytes() { return rawBytes_; } Ref DecoderResult::getText() { - return text_; + return text_; +} + +string DecoderResult::charSet() +{ + return charSet_; } diff --git a/source/zxing/zxing/common/DecoderResult.h b/source/zxing/zxing/common/DecoderResult.h index 9a1f7fa..947dd4c 100644 --- a/source/zxing/zxing/common/DecoderResult.h +++ b/source/zxing/zxing/common/DecoderResult.h @@ -33,17 +33,21 @@ private: Ref text_; ArrayRef< ArrayRef > byteSegments_; std::string ecLevel_; + std::string charSet_; public: DecoderResult(ArrayRef rawBytes, Ref text, ArrayRef< ArrayRef >& byteSegments, - std::string const& ecLevel); + std::string const& ecLevel, + std::string charSet = ""); DecoderResult(ArrayRef rawBytes, Ref text); ArrayRef getRawBytes(); Ref getText(); + // NOTE: my + std::string charSet(); }; } diff --git a/source/zxing/zxing/qrcode/QRCodeReader.cpp b/source/zxing/zxing/qrcode/QRCodeReader.cpp index 0e647ea..dee6606 100644 --- a/source/zxing/zxing/qrcode/QRCodeReader.cpp +++ b/source/zxing/zxing/qrcode/QRCodeReader.cpp @@ -31,14 +31,14 @@ namespace zxing { QRCodeReader::QRCodeReader() :decoder_() { } - //TODO: see if any of the other files in the qrcode tree need tryHarder + //TODO : see if any of the other files in the qrcode tree need tryHarder Ref QRCodeReader::decode(Ref image, DecodeHints hints) { Detector detector(image->getBlackMatrix()); Ref detectorResult(detector.detect(hints)); ArrayRef< Ref > points (detectorResult->getPoints()); Ref decoderResult(decoder_.decode(detectorResult->getBits())); Ref result( - new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE)); + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat::QR_CODE, decoderResult->charSet())); return result; } diff --git a/source/zxing/zxing/qrcode/decoder/DecodedBitStreamParser.h b/source/zxing/zxing/qrcode/decoder/DecodedBitStreamParser.h index 6f4d7d3..ac3e1f5 100644 --- a/source/zxing/zxing/qrcode/decoder/DecodedBitStreamParser.h +++ b/source/zxing/zxing/qrcode/decoder/DecodedBitStreamParser.h @@ -47,7 +47,7 @@ private: static void decodeHanziSegment(Ref bits, std::string &result, int count); static void decodeKanjiSegment(Ref bits, std::string &result, int count); static void decodeByteSegment(Ref bits, std::string &result, int count); - static void decodeByteSegment(Ref bits_, + static std::string decodeByteSegment(Ref bits_, std::string& result, int count, zxing::common::CharacterSetECI* currentCharacterSetECI, diff --git a/source/zxing/zxing/qrcode/decoder/QRDecodedBitStreamParser.cpp b/source/zxing/zxing/qrcode/decoder/QRDecodedBitStreamParser.cpp index fe7bc65..fa7d9f5 100644 --- a/source/zxing/zxing/qrcode/decoder/QRDecodedBitStreamParser.cpp +++ b/source/zxing/zxing/qrcode/decoder/QRDecodedBitStreamParser.cpp @@ -28,7 +28,7 @@ #include #endif -// Required for compatibility. TODO: test on Symbian +// Required for compatibility. TODO : test on Symbian #ifdef ZXING_ICONV_CONST #undef ICONV_CONST #define ICONV_CONST const @@ -46,18 +46,18 @@ 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', - 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' - }; +{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' +}; namespace {int GB2312_SUBSET = 1;} void DecodedBitStreamParser::append(std::string &result, string const& in, const char *src) { - append(result, (char const*)in.c_str(), in.length(), src); + append(result, (char const*)in.c_str(), in.length(), src); } void DecodedBitStreamParser::append(std::string &result, @@ -65,286 +65,288 @@ void DecodedBitStreamParser::append(std::string &result, size_t nIn, const char *src) { #ifndef NO_ICONV - if (nIn == 0) { - return; - } + if (nIn == 0) { + return; + } - iconv_t cd = iconv_open(StringUtils::UTF8, src); - if (cd == (iconv_t)-1) { - result.append((const char *)bufIn, nIn); - return; - } + 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; - char* bufOut = new char[maxOut]; + const int maxOut = 4 * nIn + 1; + char* bufOut = new char[maxOut]; - ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn; - size_t nFrom = nIn; - char *toPtr = (char *)bufOut; - size_t nTo = maxOut; + ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn; + size_t nFrom = nIn; + char *toPtr = (char *)bufOut; + size_t nTo = maxOut; - while (nFrom > 0) { + while (nFrom > 0) { #if defined(Q_OS_SYMBIAN) size_t oneway = iconv(cd,(const char**) &fromPtr, &nFrom, &toPtr, &nTo); #else size_t oneway = iconv(cd,(char**) &fromPtr, &nFrom, &toPtr, &nTo); #endif - if (oneway == (size_t)(-1)) { - iconv_close(cd); - delete[] bufOut; - throw ReaderException("error converting characters"); + if (oneway == (size_t)(-1)) { + iconv_close(cd); + delete[] bufOut; + throw ReaderException("error converting characters"); + } } - } - iconv_close(cd); + iconv_close(cd); - int nResult = maxOut - nTo; - bufOut[nResult] = '\0'; - result.append((const char *)bufOut); - delete[] bufOut; + int nResult = maxOut - nTo; + bufOut[nResult] = '\0'; + result.append((const char *)bufOut); + delete[] bufOut; #else - result.append((const char *)bufIn, nIn); + Q_UNUSED(src); + result.append((const char *)bufIn, nIn); #endif } void DecodedBitStreamParser::decodeHanziSegment(Ref 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; - char* buffer = new 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; + 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; + char* buffer = new 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] = (char) ((assembledTwoBytes >> 8) & 0xFF); + buffer[offset + 1] = (char) (assembledTwoBytes & 0xFF); + offset += 2; + count--; + } + + try { + append(result, buffer, nBytes, StringUtils::GB2312); + } catch (ReaderException const& ignored) { + (void)ignored; + delete [] buffer; + throw FormatException(); } - buffer[offset] = (char) ((assembledTwoBytes >> 8) & 0xFF); - buffer[offset + 1] = (char) (assembledTwoBytes & 0xFF); - offset += 2; - count--; - } - try { - append(result, buffer, nBytes, StringUtils::GB2312); - } catch (ReaderException const& ignored) { - (void)ignored; delete [] buffer; - throw FormatException(); - } - - delete [] buffer; } void DecodedBitStreamParser::decodeKanjiSegment(Ref 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 - size_t nBytes = 2 * count; - char* buffer = new char[nBytes]; - int offset = 0; - while (count > 0) { - // Each 13 bits encodes a 2-byte character + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as Shift_JIS afterwards + size_t nBytes = 2 * count; + char* buffer = new char[nBytes]; + int offset = 0; + while (count > 0) { + // Each 13 bits encodes a 2-byte character - int twoBytes = bits->readBits(13); - int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); - if (assembledTwoBytes < 0x01F00) { - // In the 0x8140 to 0x9FFC range - assembledTwoBytes += 0x08140; - } else { - // In the 0xE040 to 0xEBBF range - assembledTwoBytes += 0x0C140; + int twoBytes = bits->readBits(13); + int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); + if (assembledTwoBytes < 0x01F00) { + // In the 0x8140 to 0x9FFC range + assembledTwoBytes += 0x08140; + } else { + // In the 0xE040 to 0xEBBF range + assembledTwoBytes += 0x0C140; + } + buffer[offset] = (char)(assembledTwoBytes >> 8); + buffer[offset + 1] = (char)assembledTwoBytes; + offset += 2; + count--; } - buffer[offset] = (char)(assembledTwoBytes >> 8); - buffer[offset + 1] = (char)assembledTwoBytes; - offset += 2; - count--; - } - try { - append(result, buffer, nBytes, StringUtils::SHIFT_JIS); - } catch (ReaderException const& ignored) { - (void)ignored; - delete [] buffer; - throw FormatException(); - } - delete[] buffer; + try { + append(result, buffer, nBytes, StringUtils::SHIFT_JIS); + } catch (ReaderException const& ignored) { + (void)ignored; + delete [] buffer; + throw FormatException(); + } + delete[] buffer; } -void DecodedBitStreamParser::decodeByteSegment(Ref bits_, - string& result, - int count, - CharacterSetECI* currentCharacterSetECI, - ArrayRef< ArrayRef >& byteSegments, - Hashtable const& hints) { - int nBytes = count; - BitSource& bits (*bits_); - // Don't crash trying to read more bits than we have available. - if (count << 3 > bits.available()) { - throw FormatException(); - } +std::string DecodedBitStreamParser::decodeByteSegment(Ref bits_, + string& result, + int count, + CharacterSetECI* currentCharacterSetECI, + ArrayRef< ArrayRef >& byteSegments, + Hashtable const& hints) { + int nBytes = count; + BitSource& bits (*bits_); + // Don't crash trying to read more bits than we have available. + if (count << 3 > bits.available()) { + throw FormatException(); + } - ArrayRef bytes_ (count); - char* readBytes = &(*bytes_)[0]; - for (int i = 0; i < count; i++) { - readBytes[i] = (char) bits.readBits(8); - } - 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->name(); - } - try { - append(result, readBytes, nBytes, encoding.c_str()); - } catch (ReaderException const& ignored) { - (void)ignored; - throw FormatException(); - } - byteSegments->values().push_back(bytes_); + ArrayRef bytes_ (count); + char* readBytes = &(*bytes_)[0]; + for (int i = 0; i < count; i++) { + readBytes[i] = (char) bits.readBits(8); + } + 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->name(); + } + try { + append(result, readBytes, nBytes, encoding.c_str()); + } catch (ReaderException const& ignored) { + (void)ignored; + throw FormatException(); + } + byteSegments->values().push_back(bytes_); + return encoding; } void DecodedBitStreamParser::decodeNumericSegment(Ref bits, std::string &result, int count) { - int nBytes = count; - char* bytes = new char[nBytes]; - int i = 0; - // Read three digits at a time - while (count >= 3) { - // Each 10 bits encodes three digits - if (bits->available() < 10) { - throw ReaderException("format exception"); + int nBytes = count; + char* bytes = new char[nBytes]; + int i = 0; + // Read three digits at a time + while (count >= 3) { + // Each 10 bits encodes three digits + if (bits->available() < 10) { + throw ReaderException("format exception"); + } + int threeDigitsBits = bits->readBits(10); + if (threeDigitsBits >= 1000) { + ostringstream s; + s << "Illegal value for 3-digit unit: " << threeDigitsBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100]; + bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]; + bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10]; + count -= 3; } - int threeDigitsBits = bits->readBits(10); - if (threeDigitsBits >= 1000) { - ostringstream s; - s << "Illegal value for 3-digit unit: " << threeDigitsBits; - delete[] bytes; - throw ReaderException(s.str().c_str()); + if (count == 2) { + if (bits->available() < 7) { + throw ReaderException("format exception"); + } + // Two digits left over to read, encoded in 7 bits + int twoDigitsBits = bits->readBits(7); + if (twoDigitsBits >= 100) { + ostringstream s; + s << "Illegal value for 2-digit unit: " << twoDigitsBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10]; + bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10]; + } else if (count == 1) { + if (bits->available() < 4) { + throw ReaderException("format exception"); + } + // One digit left over to read + int digitBits = bits->readBits(4); + if (digitBits >= 10) { + ostringstream s; + s << "Illegal value for digit unit: " << digitBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[digitBits]; } - bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100]; - bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]; - bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10]; - count -= 3; - } - if (count == 2) { - if (bits->available() < 7) { - throw ReaderException("format exception"); - } - // Two digits left over to read, encoded in 7 bits - int twoDigitsBits = bits->readBits(7); - if (twoDigitsBits >= 100) { - ostringstream s; - s << "Illegal value for 2-digit unit: " << twoDigitsBits; - delete[] bytes; - throw ReaderException(s.str().c_str()); - } - bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10]; - bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10]; - } else if (count == 1) { - if (bits->available() < 4) { - throw ReaderException("format exception"); - } - // One digit left over to read - int digitBits = bits->readBits(4); - if (digitBits >= 10) { - ostringstream s; - s << "Illegal value for digit unit: " << digitBits; - delete[] bytes; - throw ReaderException(s.str().c_str()); - } - bytes[i++] = ALPHANUMERIC_CHARS[digitBits]; - } - append(result, bytes, nBytes, StringUtils::ASCII); - delete[] bytes; + append(result, bytes, nBytes, StringUtils::ASCII); + delete[] bytes; } char DecodedBitStreamParser::toAlphaNumericChar(size_t value) { - if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) { - throw FormatException(); - } - return ALPHANUMERIC_CHARS[value]; + if (value >= sizeof(DecodedBitStreamParser::ALPHANUMERIC_CHARS)) { + throw FormatException(); + } + return ALPHANUMERIC_CHARS[value]; } void DecodedBitStreamParser::decodeAlphanumericSegment(Ref bits_, string& result, int count, bool fc1InEffect) { - BitSource& bits (*bits_); - ostringstream bytes; - // Read two characters at a time - while (count > 1) { - if (bits.available() < 11) { - throw FormatException(); - } - int nextTwoCharsBits = bits.readBits(11); - bytes << toAlphaNumericChar(nextTwoCharsBits / 45); - bytes << toAlphaNumericChar(nextTwoCharsBits % 45); - count -= 2; - } - if (count == 1) { - // special case: one character left - if (bits.available() < 6) { - throw FormatException(); - } - bytes << toAlphaNumericChar(bits.readBits(6)); - } - // 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 { - if (i < s.length() - 1 && s[i + 1] == '%') { - // %% is rendered as % - r << s[i++]; - } else { - // In alpha mode, % should be converted to FNC1 separator 0x1D - r << (char)0x1D; + BitSource& bits (*bits_); + ostringstream bytes; + // Read two characters at a time + while (count > 1) { + if (bits.available() < 11) { + throw FormatException(); } - } + int nextTwoCharsBits = bits.readBits(11); + bytes << toAlphaNumericChar(nextTwoCharsBits / 45); + bytes << toAlphaNumericChar(nextTwoCharsBits % 45); + count -= 2; } - s = r.str(); - } - append(result, s, StringUtils::ASCII); + if (count == 1) { + // special case: one character left + if (bits.available() < 6) { + throw FormatException(); + } + bytes << toAlphaNumericChar(bits.readBits(6)); + } + // 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 { + if (i < s.length() - 1 && s[i + 1] == '%') { + // %% is rendered as % + r << s[i++]; + } else { + // In alpha mode, % should be converted to FNC1 separator 0x1D + r << (char)0x1D; + } + } + } + s = r.str(); + } + append(result, s, StringUtils::ASCII); } namespace { - int parseECIValue(BitSource& bits) { +int parseECIValue(BitSource& bits) { int firstByte = bits.readBits(8); if ((firstByte & 0x80) == 0) { - // just one byte - return firstByte & 0x7F; + // just one byte + return firstByte & 0x7F; } if ((firstByte & 0xC0) == 0x80) { - // two bytes - int secondByte = bits.readBits(8); - return ((firstByte & 0x3F) << 8) | secondByte; + // 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; + // three bytes + int secondThirdBytes = bits.readBits(16); + return ((firstByte & 0x1F) << 16) | secondThirdBytes; } throw FormatException(); - } +} } Ref @@ -352,80 +354,80 @@ DecodedBitStreamParser::decode(ArrayRef bytes, Version* version, ErrorCorrectionLevel const& ecLevel, Hashtable const& hints) { - Ref bits_ (new BitSource(bytes)); - BitSource& bits (*bits_); - string result; - result.reserve(50); - ArrayRef< ArrayRef > byteSegments (0); - try { + Ref bits_ (new BitSource(bytes)); + BitSource& bits (*bits_); + string result; + result.reserve(50); + ArrayRef< ArrayRef > byteSegments (0); CharacterSetECI* currentCharacterSetECI = 0; - bool fc1InEffect = false; - 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; - } else { - try { - mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits - } catch (IllegalArgumentException const& iae) { - throw iae; - // throw FormatException.getFormatInstance(); - } - } - 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 == &Mode::STRUCTURED_APPEND) { - if (bits.available() < 16) { - throw FormatException(); - } - // 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 == &Mode::ECI) { - // Count doesn't apply to ECI - int value = parseECIValue(bits); - currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value); - if (currentCharacterSetECI == 0) { - throw FormatException(); - } - } else { - // First handle Hanzi mode which does not start with character count - 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)); - if (subset == GB2312_SUBSET) { - 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 == &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); + string charSet = ""; + try { + bool fc1InEffect = false; + 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; } else { - throw FormatException(); + try { + mode = &Mode::forBits(bits.readBits(4)); // mode is encoded by 4 bits + } catch (IllegalArgumentException const& iae) { + throw iae; + // throw FormatException.getFormatInstance(); + } } - } - } - } - } while (mode != &Mode::TERMINATOR); - } catch (IllegalArgumentException const& iae) { - (void)iae; - // from readBits() calls - throw FormatException(); - } - - return Ref(new DecoderResult(bytes, Ref(new String(result)), byteSegments, (string)ecLevel)); + 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 == &Mode::STRUCTURED_APPEND) { + if (bits.available() < 16) { + throw FormatException(); + } + // 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 == &Mode::ECI) { + // Count doesn't apply to ECI + int value = parseECIValue(bits); + currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value); + if (currentCharacterSetECI == 0) { + throw FormatException(); + } + } else { + // First handle Hanzi mode which does not start with character count + 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)); + if (subset == GB2312_SUBSET) { + 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 == &Mode::NUMERIC) { + decodeNumericSegment(bits_, result, count); + } else if (mode == &Mode::ALPHANUMERIC) { + decodeAlphanumericSegment(bits_, result, count, fc1InEffect); + } else if (mode == &Mode::BYTE) { + charSet = decodeByteSegment(bits_, result, count, currentCharacterSetECI, byteSegments, hints); + } else if (mode == &Mode::KANJI) { + decodeKanjiSegment(bits_, result, count); + } else { + throw FormatException(); + } + } + } + } + } while (mode != &Mode::TERMINATOR); + } catch (IllegalArgumentException const& iae) { + (void)iae; + // from readBits() calls + throw FormatException(); + } + return Ref(new DecoderResult(bytes, Ref(new String(result)), byteSegments, (string)ecLevel, charSet)); } diff --git a/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp b/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp index fe8d785..9bbc8cc 100644 --- a/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp +++ b/source/zxing/zxing/qrcode/encoder/MatrixUtil.cpp @@ -226,7 +226,7 @@ int MatrixUtil::findMSBSet(int value) { int numDigits = 0; while (value != 0) { - (size_t)value >> 1; // ??value >>>= 1; + value >>= 1; ++numDigits; } return numDigits;