From c5b03f665a601c64826c28ebbb2ef9ebc3d3c26d Mon Sep 17 00:00:00 2001 From: gitlost Date: Mon, 2 Sep 2019 11:43:14 +0100 Subject: [PATCH] Fix microqr version option out-by-one --- backend/qr.c | 34 +++++---- backend/tests/CMakeLists.txt | 3 +- backend/tests/test_maxicode.c | 4 +- backend/tests/test_qr.c | 132 ++++++++++++++++++++++++++++++++++ frontend_qt/mainwindow.cpp | 2 +- 5 files changed, 159 insertions(+), 16 deletions(-) create mode 100644 backend/tests/test_qr.c diff --git a/backend/qr.c b/backend/qr.c index ef3ea37d..5683ac22 100644 --- a/backend/qr.c +++ b/backend/qr.c @@ -2586,6 +2586,26 @@ int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t len return ZINT_ERROR_TOO_LONG; } + /* Check option 1 in combination with option 2 */ + ecc_level = LEVEL_L; + if (symbol->option_1 >= 1 && symbol->option_1 <= 4) { + if (symbol->option_1 == 4) { + strcpy(symbol->errtxt, "566: Error correction level H not available"); + return ZINT_ERROR_INVALID_OPTION; + } + if (symbol->option_2 >= 1 && symbol->option_2 <= 4) { + if (symbol->option_2 == 1 && symbol->option_1 != 1) { + strcpy(symbol->errtxt, "574: Version M1 supports error correction level L only"); + return ZINT_ERROR_INVALID_OPTION; + } + if (symbol->option_2 != 4 && symbol->option_1 == 3) { + strcpy(symbol->errtxt, "575: Error correction level Q requires Version M4"); + return ZINT_ERROR_INVALID_OPTION; + } + } + ecc_level = symbol->option_1; + } + for (i = 0; i < 4; i++) { version_valid[i] = 1; } @@ -2688,16 +2708,6 @@ int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t len } /* Eliminate possible versions depending on error correction level specified */ - ecc_level = LEVEL_L; - if ((symbol->option_1 >= 1) && (symbol->option_2 <= 4)) { - ecc_level = symbol->option_1; - } - - if (ecc_level == LEVEL_H) { - strcpy(symbol->errtxt, "566: Error correction level H not available"); - return ZINT_ERROR_INVALID_OPTION; - } - if (ecc_level == LEVEL_Q) { version_valid[0] = 0; version_valid[1] = 0; @@ -2736,8 +2746,8 @@ int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t len version = autoversion; /* Get version from user */ if ((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) { - if (symbol->option_2 >= autoversion) { - version = symbol->option_2; + if (symbol->option_2 - 1 >= autoversion) { + version = symbol->option_2 - 1; } else { strcpy(symbol->errtxt, "570: Input too long for selected symbol size"); return ZINT_ERROR_TOO_LONG; diff --git a/backend/tests/CMakeLists.txt b/backend/tests/CMakeLists.txt index bdabad5e..3c7ceb14 100644 --- a/backend/tests/CMakeLists.txt +++ b/backend/tests/CMakeLists.txt @@ -11,7 +11,7 @@ set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/" set(ZINT_DEBUG FALSE CACHE BOOL "Set debug compile flag") set(ZINT_SANITIZE FALSE CACHE BOOL "Set sanitize compile/link flags") -find_package (LibZint 2.6.3 REQUIRED) +find_package (LibZint 2.6.4 REQUIRED) if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") if (ZINT_DEBUG) @@ -40,5 +40,6 @@ zint_add_test(eci, test_eci) zint_add_test(imail, test_imail) zint_add_test(mailmark, test_mailmark) zint_add_test(maxicode, test_maxicode) +zint_add_test(qr, test_qr) zint_add_test(rss, test_rss) zint_add_test(upcean, test_upcean) diff --git a/backend/tests/test_maxicode.c b/backend/tests/test_maxicode.c index a9cd885a..dac9ce29 100644 --- a/backend/tests/test_maxicode.c +++ b/backend/tests/test_maxicode.c @@ -33,7 +33,7 @@ #include #include "testcommon.h" -//#define TEST_RSS_GENERATE_EXPECTED 1 +//#define TEST_GENERATE_EXPECTED 1 static void test_best_supported_set(void) { @@ -105,7 +105,7 @@ static void test_best_supported_set(void) ret = ZBarcode_Render( symbol, data[i].w, data[i].h ); assert_equal(ret, data[i].ret_render, "i:%d ZBarcode_Render ret %d != %d\n", i, ret, data[i].ret_render); - #ifdef TEST_RSS_GENERATE_EXPECTED + #ifdef TEST_GENERATE_EXPECTED printf("symbology %d, data %s, length %d, rows %d, width %d\n", symbol->symbology, data[i].data, length, symbol->rows, symbol->width); testUtilModulesDump(symbol); #else diff --git a/backend/tests/test_qr.c b/backend/tests/test_qr.c new file mode 100644 index 00000000..442b146e --- /dev/null +++ b/backend/tests/test_qr.c @@ -0,0 +1,132 @@ +/* + libzint - the open source barcode library + Copyright (C) 2008-2019 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ + +#include "testcommon.h" + +static void test_microqr_options(void) +{ + testStart(""); + + int ret; + struct item { + unsigned char* data; + int option_1; + int option_2; + int ret_encode; + float w; + float h; + int ret_render; + int expected_size; + }; + struct item data[] = { + /* 0*/ { "12345", 0, 0, 0, 100, 100, 1, 11 }, + /* 1*/ { "12345", 1, 0, 0, 100, 100, 1, 11 }, + /* 2*/ { "12345", 2, 0, 0, 100, 100, 1, 13 }, + /* 3*/ { "12345", 3, 0, 0, 100, 100, 1, 17 }, + /* 4*/ { "12345", 4, 0, ZINT_ERROR_INVALID_OPTION, 100, 100, -1, 0 }, + /* 5*/ { "12345", 0, 1, 0, 100, 100, 1, 11 }, + /* 6*/ { "12345", 0, 2, 0, 100, 100, 1, 13 }, + /* 7*/ { "12345", 0, 3, 0, 100, 100, 1, 15 }, + /* 8*/ { "12345", 0, 4, 0, 100, 100, 1, 17 }, + /* 9*/ { "12345", 0, 5, 0, 100, 100, 1, 11 }, // Size > 4 ignored + /*10*/ { "12345", 1, 5, 0, 100, 100, 1, 11 }, // Ignored also if ECC given + /*11*/ { "12345", 1, 1, 0, 100, 100, 1, 11 }, + /*12*/ { "12345", 1, 2, 0, 100, 100, 1, 13 }, + /*13*/ { "12345", 1, 3, 0, 100, 100, 1, 15 }, + /*14*/ { "12345", 1, 4, 0, 100, 100, 1, 17 }, + /*15*/ { "12345", 2, 1, ZINT_ERROR_INVALID_OPTION, 100, 100, -1, 0 }, + /*16*/ { "12345", 2, 2, 0, 100, 100, -1, 13 }, + /*17*/ { "12345", 2, 3, 0, 100, 100, -1, 15 }, + /*18*/ { "12345", 2, 4, 0, 100, 100, -1, 17 }, + /*19*/ { "12345", 3, 1, ZINT_ERROR_INVALID_OPTION, 100, 100, -1, 0 }, + /*20*/ { "12345", 3, 2, ZINT_ERROR_INVALID_OPTION, 100, 100, -1, 0 }, + /*21*/ { "12345", 3, 3, ZINT_ERROR_INVALID_OPTION, 100, 100, -1, 0 }, + /*22*/ { "12345", 3, 4, 0, 100, 100, -1, 17 }, + /*23*/ { "12345", 4, 4, ZINT_ERROR_INVALID_OPTION, 100, 100, -1, 0 }, + /*24*/ { "12345", 5, 0, 0, 100, 100, 1, 11 }, // ECC > 4 ignored + /*25*/ { "12345", 5, 1, 0, 100, 100, 1, 11 }, // Ignored also if size given + + /*26*/ { "123456", 1, 0, 0, 100, 100, 1, 13 }, + /*27*/ { "123456", 1, 1, ZINT_ERROR_TOO_LONG, 100, 100, -1, 0 }, + /*28*/ { "123456", 1, 2, 0, 100, 100, 1, 13 }, + + /*29*/ { "ABCDEF", 1, 0, 0, 100, 100, 1, 13 }, + /*30*/ { "ABCDEF", 1, 2, 0, 100, 100, 1, 13 }, + /*31*/ { "ABCDEF", 2, 2, ZINT_ERROR_TOO_LONG, 100, 100, -1, 0 }, + /*32*/ { "ABCDE", 2, 0, 0, 100, 100, 1, 13 }, + + /*33*/ { "ABCDEABCDEABCD", 1, 0, 0, 100, 100, 1, 15 }, // 14 alphanumerics + /*34*/ { "ABCDEABCDEABCD", 1, 3, 0, 100, 100, 1, 15 }, + /*35*/ { "ABCDEABCDEABCD", 2, 3, ZINT_ERROR_TOO_LONG, 100, 100, -1, 0 }, + /*36*/ { "ABCDEABCDEA", 2, 3, 0, 100, 100, 1, 15 }, // 11 alphanumerics + + /*37*/ { "ABCDEFGHIJABCDEFGHIJA", 1, 0, 0, 100, 100, 1, 17 }, // 21 alphanumerics + /*38*/ { "ABCDEFGHIJABCDEFGHIJA", 1, 4, 0, 100, 100, 1, 17 }, + /*39*/ { "ABCDEFGHIJABCDEFGHIJA", 2, 4, ZINT_ERROR_TOO_LONG, 100, 100, -1, 0 }, + /*40*/ { "ABCDEFGHIJABCDEFGH", 2, 4, 0, 100, 100, 1, 17 }, // 18 alphanumerics + /*41*/ { "ABCDEFGHIJABCDEFGH", 3, 4, ZINT_ERROR_TOO_LONG, 100, 100, -1, 0 }, + /*42*/ { "ABCDEFGHIJABC", 3, 4, 0, 100, 100, 1, 17 }, // 13 alphanumerics + }; + int data_size = sizeof(data) / sizeof(struct item); + + for (int i = 0; i < data_size; i++) { + + struct zint_symbol* symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + symbol->symbology = BARCODE_MICROQR; + symbol->option_1 = data[i].option_1; + symbol->option_2 = data[i].option_2; + int length = strlen(data[i].data); + + ret = ZBarcode_Encode(symbol, data[i].data, length); + assert_equal(ret, data[i].ret_encode, "i:%d ZBarcode_Encode ret %d != %d\n", i, ret, data[i].ret_encode); + + if (data[i].ret_render != -1) { + ret = ZBarcode_Render( symbol, data[i].w, data[i].h ); + assert_equal(ret, data[i].ret_render, "i:%d ZBarcode_Render ret %d != %d\n", i, ret, data[i].ret_render); + assert_equal(symbol->width, data[i].expected_size, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_size); + assert_equal(symbol->rows, data[i].expected_size, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_size); + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +int main() +{ + test_microqr_options(); + + testReport(); + + return 0; +} diff --git a/frontend_qt/mainwindow.cpp b/frontend_qt/mainwindow.cpp index 37c9f61c..8f15a3fc 100644 --- a/frontend_qt/mainwindow.cpp +++ b/frontend_qt/mainwindow.cpp @@ -966,7 +966,7 @@ void MainWindow::update_preview() case BARCODE_MICROQR: m_bc.bc.setSymbol(BARCODE_MICROQR); if(m_optionWidget->findChild("radMQRSize")->isChecked()) - m_bc.bc.setWidth(m_optionWidget->findChild("cmbMQRSize")->currentIndex()); + m_bc.bc.setWidth(m_optionWidget->findChild("cmbMQRSize")->currentIndex() + 1); if(m_optionWidget->findChild("radMQRECC")->isChecked()) m_bc.bc.setSecurityLevel(m_optionWidget->findChild("cmbMQRECC")->currentIndex() + 1);