diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:43:19 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:43:19 +0300 |
| commit | 5c7048091e3a191e8a34f26852a8976b254e339b (patch) | |
| tree | f1008a55d8ecb3304b5f51ea549156eaba21843b | |
| parent | 5fad10f89c485cfdc7b99011f07609f8871160d4 (diff) | |
| parent | 49980df270e6a39738a0c886c1eef6b42e782edb (diff) | |
| download | Project-Tick-5c7048091e3a191e8a34f26852a8976b254e339b.tar.gz Project-Tick-5c7048091e3a191e8a34f26852a8976b254e339b.zip | |
Add 'genqrcode/' from commit '49980df270e6a39738a0c886c1eef6b42e782edb'
git-subtree-dir: genqrcode
git-subtree-mainline: 5fad10f89c485cfdc7b99011f07609f8871160d4
git-subtree-split: 49980df270e6a39738a0c886c1eef6b42e782edb
75 files changed, 24746 insertions, 0 deletions
diff --git a/genqrcode/.github/workflows/cmake.yml b/genqrcode/.github/workflows/cmake.yml new file mode 100644 index 0000000000..1fd5c4d65d --- /dev/null +++ b/genqrcode/.github/workflows/cmake.yml @@ -0,0 +1,55 @@ +name: CMake-build + +on: [push, pull_request] + +env: + BUILD_TYPE: Release + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v2 + + - name: run vcpkg + if: matrix.os == 'windows-latest' + uses: lukka/run-vcpkg@v6 + with: + vcpkgArguments: getopt:x64-windows libiconv:x64-windows libpng:x64-windows + vcpkgDirectory: '${{ github.workspace }}/vcpkg' + vcpkgGitCommitId: '2a42024b53ebb512fb5dd63c523338bf26c8489c' + appendedCacheKey: ${{ hashFiles( '${{ github.workspace }}/.github/workflows/cmake.yml' ) }} + + - name: brew setup + if: matrix.os == 'macos-latest' + run: brew install pkg-config libpng + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + if: matrix.os != 'windows-latest' + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DWITH_TESTS=yes -DBUILD_SHARED_LIBS=on + + - name: Configure CMake for Windows + if: matrix.os == 'windows-latest' + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake -DWITH_TESTS=yes + + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake --build . --config $BUILD_TYPE -j 2 + + - name: Test + working-directory: ${{runner.workspace}}/build + shell: bash + run: ctest -C $BUILD_TYPE diff --git a/genqrcode/.github/workflows/configure.yml b/genqrcode/.github/workflows/configure.yml new file mode 100644 index 0000000000..6fcf4d1a13 --- /dev/null +++ b/genqrcode/.github/workflows/configure.yml @@ -0,0 +1,26 @@ +name: build + +on: [push, pull_request] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + + steps: + - uses: actions/checkout@v2 + - name: brew setup + if: matrix.os == 'macos-latest' + run: brew install automake autoconf pkg-config libpng + - name: generate configure script + run: ./autogen.sh + - name: configure + run: ./configure --with-tests + - name: make + run: make -j 2 + - name: make check + run: make check + - name: make distcheck + run: make -j 2 distcheck diff --git a/genqrcode/.gitignore b/genqrcode/.gitignore new file mode 100644 index 0000000000..4b558b6c30 --- /dev/null +++ b/genqrcode/.gitignore @@ -0,0 +1,58 @@ +*.[oa] +*.lo +*.la +*.gcno +*.gcov +*.gcda +.deps/ +.libs/ +autom4te.cache/ +m4/ +CMakeLists.txt.user +CMakeCache.txt +CTestTestfile.cmake +CMakeFiles/ +cmake_install.cmake +Makefile +Makefile.in +README +build +config.log +configure +config.status +config.h +config.h.in +aclocal.m4 +libtool +stamp-h1 +qrencode +qrencode.1 +libqrencode.pc +tests/create_frame_pattern +tests/create_mqr_frame_pattern +tests/pthread_qrencode +tests/prof_qrencode +tests/test_bitstream +tests/test_estimatebit +tests/test_mask +tests/test_mmask +tests/test_monkey +tests/test_mqrspec +tests/test_qrencode +tests/test_qrinput +tests/test_qrspec +tests/test_rs +tests/test_split +tests/test_split_urls +tests/view_qrcode +use/compile +use/config.guess +use/config.sub +use/depcomp +use/install-sh +use/ltmain.sh +use/missing +use/test-driver +html/ +massif.out.* +gmon.out diff --git a/genqrcode/CMakeLists.txt b/genqrcode/CMakeLists.txt new file mode 100644 index 0000000000..773e037492 --- /dev/null +++ b/genqrcode/CMakeLists.txt @@ -0,0 +1,201 @@ +cmake_minimum_required(VERSION 3.1.0) + +project(QRencode VERSION 4.1.1 LANGUAGES C) + +option(WITH_TOOLS "Build utility tools" YES ) +option(WITH_TESTS "Build tests" NO ) +option(WITHOUT_PNG "Disable PNG support" NO) +option(GPROF "Generate extra code to write profile information" OFF) +option(COVERAGE "Generate extra code to write coverage information" OFF) +option(ASAN "Use AddressSanitizer" OFF) +option(BUILD_SHARED_LIBS "Enable build of shared libraries" NO) + +if(BUILD_TESTING) + set(WITH_TESTS ON) + message(DEPRECATION "use WITH_TESTS option instead BUILD_TESTING") +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +set(CMAKE_THREAD_PREFER_PTHREAD ON) +find_package(Threads) +find_package(PNG) +find_package(Iconv) + +if(CMAKE_USE_PTHREADS_INIT) + add_definitions(-DHAVE_LIBPTHREAD=1) + # for libqrencode.pc + set(LIBPTHREAD ${CMAKE_THREAD_LIBS_INIT}) +endif() + +## Check for system include files +include(CheckIncludeFile) +include(CheckFunctionExists) + +check_include_file(dlfcn.h HAVE_DLFCN_H ) +check_include_file(inttypes.h HAVE_INTTYPES_H) +check_include_file(memory.h HAVE_MEMORY_H ) +check_include_file(stdint.h HAVE_STDINT_H ) +check_include_file(stdlib.h HAVE_STDLIB_H ) +check_include_file(strings.h HAVE_STRINGS_H ) +check_include_file(string.h HAVE_STRING_H ) +check_include_file(getopt.h HAVE_GETOPT_H ) +check_include_file(sys/time.h HAVE_SYS_TIME_H) +check_include_file(time.h HAVE_TIME_H ) +check_include_file(pthread.h HAVE_PTHREAD_H ) + +check_function_exists(strdup HAVE_STRDUP) + +if(HAVE_STRDUP) + add_definitions(-DHAVE_STRDUP=1) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +endif() + +if(GPROF) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") +endif() + +if(COVERAGE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") +endif() + +if(ASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls") +endif() + +add_definitions(-DMAJOR_VERSION=${PROJECT_VERSION_MAJOR}) +add_definitions(-DMINOR_VERSION=${PROJECT_VERSION_MINOR}) +add_definitions(-DMICRO_VERSION=${PROJECT_VERSION_PATCH}) +add_definitions(-DVERSION="${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") +add_definitions(-DHAVE_SDL=0) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + + add_definitions(-Dstrcasecmp=_stricmp) + add_definitions(-Dstrncasecmp=_strnicmp) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) + + if(WITH_TOOLS) + find_path(GETOPT_INCLUDE_DIR getopt.h PATH_SUFFIXES include) + find_library(GETOPT_LIBRARIES getopt PATH_SUFFIXES lib) + include_directories(${GETOPT_INCLUDE_DIR}) + endif(WITH_TOOLS) +endif(MSVC) + +set(QRENCODE_SRCS qrencode.c + qrinput.c + bitstream.c + qrspec.c + rsecc.c + split.c + mask.c + mqrspec.c + mmask.c) + +set(QRENCODE_HDRS qrencode_inner.h + qrinput.h + bitstream.h + qrspec.h + rsecc.h + split.h + mask.h + mqrspec.h + mmask.h) + +if(BUILD_SHARED_LIBS) + if(MSVC) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + endif() + add_library(qrencode SHARED ${QRENCODE_SRCS} ${QRENCODE_HDRS}) + set_target_properties(qrencode PROPERTIES VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} SOVERSION ${PROJECT_VERSION_MAJOR}) +else() + add_library(qrencode ${QRENCODE_SRCS} ${QRENCODE_HDRS}) +endif() +if(CMAKE_USE_PTHREADS_INIT) + target_link_libraries(qrencode Threads::Threads) +endif() + +include(GNUInstallDirs) +set(prefix "${CMAKE_INSTALL_PREFIX}") +set(exec_prefix "${CMAKE_INSTALL_FULL_BINDIR}") +set(libdir "${CMAKE_INSTALL_FULL_LIBDIR}") +set(includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") +set(VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + +configure_file(qrencode.1.in qrencode.1 @ONLY) +configure_file(libqrencode.pc.in libqrencode.pc @ONLY) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qrencode.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libqrencode.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +install(FILES qrencode.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(TARGETS qrencode DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +## Build utility tools +if(WITH_TOOLS) + if(NOT WITHOUT_PNG) + add_definitions(-DHAVE_PNG=1) + endif() + add_executable(qrenc qrenc.c) + set_target_properties(qrenc PROPERTIES OUTPUT_NAME qrencode) + + if(NOT WITHOUT_PNG) + target_link_libraries(qrenc qrencode PNG::PNG) + else() + target_link_libraries(qrenc qrencode) + endif() + + if(MSVC) + target_link_libraries(qrenc ${GETOPT_LIBRARIES}) + endif(MSVC) + + install(TARGETS qrenc DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() + +if(WITH_TESTS) + enable_testing() + add_definitions(-DWITH_TESTS=) + add_definitions(-DSTATIC_IN_RELEASE=) + add_subdirectory(tests) +else() + add_definitions(-DSTATIC_IN_RELEASE=static) +endif() + +## ============================================================================== +## +## Configuration summary +## +## ============================================================================== + +message(STATUS "------------------------------------------------------------" ) +message(STATUS "[QRencode] Configuration summary." ) +message(STATUS "------------------------------------------------------------ ") +message(STATUS " System configuration:" ) +message(STATUS " .. Processor type .............. = ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS " .. CMake executable ............ = ${CMAKE_COMMAND}" ) +message(STATUS " .. CMake version ............... = ${CMAKE_VERSION}" ) +message(STATUS " .. System name ................. = ${CMAKE_SYSTEM}" ) +message(STATUS " .. C++ compiler ................ = ${CMAKE_CXX_COMPILER}" ) +message(STATUS " .. C compiler .................. = ${CMAKE_C_COMPILER}" ) +message(STATUS " .. size(void*) ................. = ${CMAKE_SIZEOF_VOID_P}" ) +message(STATUS " Dependencies:" ) +#message(STATUS " .. Doxygen ..................... = ${DOXYGEN_EXECUTABLE}" ) +message(STATUS " .. Thread library of the system = ${CMAKE_THREAD_LIBS_INIT}") +message(STATUS " .. Iconv ....................... = ${ICONV_FOUND}" ) +message(STATUS " .... Iconv includes ............ = ${ICONV_INCLUDE_DIR}" ) +message(STATUS " .... Iconv library ............. = ${ICONV_LIBRARIES}" ) +message(STATUS " .. ZLIB ........................ = ${ZLIB_FOUND}" ) +message(STATUS " .. PNG ......................... = ${PNG_FOUND}" ) +message(STATUS " .... PNG includes .............. = ${PNG_INCLUDE_DIR}" ) +message(STATUS " .... PNG library ............... = ${PNG_LIBRARIES}" ) +#message(STATUS " .. Memory checker .............. = ${MEMORYCHECK_COMMAND}" ) +message(STATUS " Project configuration:" ) +message(STATUS " .. Build test programs ........ = ${WITH_TESTS}" ) +message(STATUS " .. Build utility tools ........ = ${WITH_TOOLS}" ) +message(STATUS " .. Disable PNG support ........ = ${WITHOUT_PNG}" ) +message(STATUS " .. Installation prefix ......... = ${CMAKE_INSTALL_PREFIX}" ) +message(STATUS "------------------------------------------------------------ ") diff --git a/genqrcode/COPYING b/genqrcode/COPYING new file mode 100644 index 0000000000..4362b49151 --- /dev/null +++ b/genqrcode/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/genqrcode/ChangeLog b/genqrcode/ChangeLog new file mode 100644 index 0000000000..79713f070d --- /dev/null +++ b/genqrcode/ChangeLog @@ -0,0 +1,1826 @@ +2021.01.08 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * tests/test_qrinput.c: + - A minor memory leak bug in a test case has been fixed. + * README.md: + - 'libpng12-dev' has been corrected to 'libpng-dev'. (closes #170) + (Thanks to @a6q) + * .github/workflows/cmake.yml: + - Updated 'run-vcpkg' package to v6. + - vcpkg's git commit ID has been updated to the latest master. + +2020.09.29 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * qrencode.c: + - Removed unused code. + * qrencode.h: + - Added a sample code snippet to the document. + +2020.09.28 Kentaro Fukuchi <kentaro@fukuchi.org> + [hotfix] + * qrinput.c, tests/test_estimatebit.c: + - Fixed a bug in the estimation of the Micro QR Code's data length + in QRinput_estimateBitStreamSizeOfEntry() has been fixed. + - Fixed a bug in the calculation of the Micro QR Code's data capacity in + QRinput_encodeBitStream(). + - A test case to test the bugs above has been added. + - Level check failure in QRinput_new2() on Windows has been fixed. + * Bumped version to 4.1.1. + [develop] + * tests/release_check.sh: + - Release checker script has been added. Currently it checks only the + version numbers among scripts. + * configure.ac: + - '--enable-mudflap' option has been deleted. (mudflap is deprecated + since GCC 4.9) + * qrencode.h: + - Comments for QRcode_APIVersion() has been slightly improved. + +2020.09.27 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * NEWS: + - All tab characters have been replaced with spaces. + * qrenc.c, qrencode.1.in: + - The effects of '--type' option's 'ASCII' and 'ASCIIi' have been + swapped. (closes #142) + * .github/workflows/{configure,cmake}.yml: + - CI scripts have been improved to utilze multiple cores and cache. + * tests/{test_basic.sh, test_qrenc.sh}: + - Code cleanups. + [code cleanups] + * various files: + - Cleanup compiler warnings. + [develop] + * Merged 'code cleanups' branch. + * qrenc.c: + - Text output bug of structured append has been fixed. + +2020.09.26 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * tests/test_qrencode.c: + - Minor memory leak bug in a test case has been fixed. + * COPYING: + - Updated to the latest revision. + * qrenc.c: + - Some URLs' schemes have been updated to https from http. + * README.md, qrenc.c, qrencode.1.in, qrencode.[ch]: + - Copyright year has been updated. + * .github/workflows/{configure,cmake,cmake-windows}.yml: + - Workflow names have been improved. + * .travis.yml: + - Migration to Github Actions has been completed. + * .github/workflows/{configure,cmake,cmake-windows}.yml: + - CI scripts have been improved. + * README.md, makeREADME.sh: + - Status badge has been changed to show the result from the Github Actions + instead of Travis CI. + +2020.09.22 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * mask.c, qrencode.h: + - Typos and grammer errors have been fixed. + * Merge branch 'optimization'. + +2020.09.21 Kentaro Fukuchi <kentaro@fukuchi.org> + [optimization] + * tests/prof_qrencode.c: + - Test numbers are extended. + * mask.c: + - Minor optimizations. + +2020.08.30 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * .github/workflows/configure.yml: + - Added macOS CI script. + * qrencode.1.in, qrenc.c: + - Detailed description of text output types has been added. + (closes #142) + * qrenc.c: + - Invalid XPM output has been fixed. (Thanks to @dlitz and @cbrt64) + (closes #136) + [optimization] + * qrencode.c: + - A tail recursion in FrameFiller_next() has been eliminated. + +2020.08.29 Kentaro Fukuchi <kentaro@fukuchi.org> + [release-4.1.0] + * .github/workflows/{cmake,configure,cmake-windows}.yml: + - Github actions CI scripts have been added. + * tests/test_bitstream.c: + - Fixed memory leak. + * configure.ac, tests/{prof,pthread}_qrencode.c: + - Make configure to define HAVE_SYS_TIME_H in config.h. + * CMakeLists.txt: + - 'wingetopt' has been replaced to 'getopt'. + * qrencode.c, tests/test_qrencode.c: + - ECLEVEL check has been improved. + * .gitignore: + - Added 'use/test-driver'. + [master] + * merged release-4.1.0. + * version 4.1.0 has been released. + +2020.08.28 Kentaro Fukuchi <kentaro@fukuchi.org> + [develop] + * Made a develoment branch. + * test_qrspec.c: + - Typo fixes. + * qrinput.[ch], tests/{test_qrencode.c, test_qrinput.c}: + - A precise boundary check has been introduced to + QRinput_estimateVersion(). (closes #160) + * qrinput.c, qrencode.c, tests/test_qrencode.c, qrenc.c, qrencode.1.in: + - QRinput_encodeMode*() now throws ERANGE when encoding Micro QR Code + and an appropriate version number was not specified. + - Now Micro QR Code also allows auto version adjustment. + * qrenc.c, qrencode.1.in: + - The synopsis has been improved. (Thanks to @jidanni) (closes #155) + - A new option '--strict-version' has been introduced. + * split.c: + - A tail recursion has been eliminated. (Thanks to @4061N) (closes #144) + * tests/*: + - All test programs are now TAP-ready. Now you can run all test programs + by 'make check'.(Thanks to @jtojnar) (closes #117) + * qrinput.c: + - Return value was ignored. (Thanks to @xiaoyur347) (closed #143) + * README.md, NEWS: + - Various documentation improvements and updates. + [release-4.1.0] + * Bumped version to 4.1.0. + * qrencode.h: + - Document improvements. + * qrenc.c, qrencode.1.in: + - Added 'UTF8i' and 'ANSIUTF8i' to the descriptions of the corresponding + options. (Thanks to @Khoyo) (merged #138) + +2020.02.23 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * CMakeLists.txt, README.md: + - Merged #158 (Thanks to @neheb): + - Fixed the compile-time issue of the environment without libpng. + +2020.02.23 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * README.md: + - Merged #151 (Thanks to @NancyLi1013): + - Added vcpkg installation instructions. + +2018.11.09 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * configure.ac, README.md: + - Merged #137 (Thanks to @abelbeck and @charmander): + - 'too many arguments' bug has been fixed. + +2018.07.28 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * CMakeLists.txt: + - Merged #133 (Thanks to @sdf5): + - Change CMAKE_SORUCE_DIR to CMAKE_CURRENT_SORUCE_DIR in + CMAKE_MODULE_PATH + +2018.06.14 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * qrenc.c, qrencode.1.in, README.md, NEWS: + - UTF8 mode now supports ANSI256 color. (Thanks to András Veres- + Szentkirályi) + +2018.06.07 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * CMakeLists.txt, tests/CMakeLists.txt: + - Merged #131 (Thanks to @mgorny): + - Update paths inside the pkg-config file to respect GNUInstallDirs. + - Improve pthread support for the main library when building via CMake. + - Always build libdecoder as static library. + +2018.06.06 Kentaro Fukuchi <kentaro@fukuchi.org> + [master, 4.0] + * tests/Makefile.am: + - Add missing test_basic.sh to EXTRA_DIST. (merged #127) (Thanks to + @mgorny) + * CMakeLists.txt: + - Use CMake GNUInstallDirs module to provide variables for configurable + install directories. (merged #128) (Thanks to @mgorny) + [4.0] + * configure.ac, CMakeLists.txt, README.md: + - Bumped version to 4.0.2. + [master] + * tests/{Makefile.am, CMakeLists.txt, test_qrspec.c}: + - Fix running test_qrspec when building out-of-source. (merged #129) + (Thanks to @mgorny) + +2018.06.04 Kentaro Fukuchi <kentaro@fukuchi.org> + [master, 4.0] + * CMakeLists.txt: + - STATIC_IN_RELEASE is now set to "static" when WITH_TESTS is disabled. + (closes #126) + - Tabs expaned. + [4.0] + * configure.ac, CMakeLists.txt, README.md: + - Bumped version to 4.0.1. + +2018.06.02 Kentaro Fukuchi <kentaro@fukuchi.org> + [master, 4.0] + * CMakeLists.txt: + - Added "WITHOUT_PNG" option that builds qrencode without PNG support. + (closes #125) + +2018.06.01 Kentaro Fukuchi <kentaro@fukuchi.org> + [master, 4.0] + * README.md: + - Added some notes of how to use autogen.sh. (closes #122) (Thanks to + @thebunnyrules) + +2017.10.20 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * qrenc.c: + - Adds the --inline option, which omits the xml tag for SVG output. + (merged #110) (Thanks to @jp-bennett) + - Short option '-I' for '--inline' disabled. + * qrencode.1.in: + - Added some missing descriptions. + * README.md: + - Acknowledgments updated. + +2017.10.13 Kentaro Fukuchi <kentaro@fukuchi.org> + [master, 4.0] + * qrencode.h: + - Fix build on windows with Visual Studio. (merged #108) (Thanks to + @Ation) + [master] + * README.md: + - libqrencode now advertised as a "fast and compact" library. + +2017.10.08 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * qrenc.c, qrinput.c, rsecc.c, tests/common.c, tests/decoder.c: + - Fixed some warnings. (closing #89 and #102) + +2017.10.06 Kentaro Fukuchi <kentaro@fukuchi.org> + [master] + * tests/test_{all,basic}.sh: + - All tests except test_configure.sh can be run by test_basic.sh now. + - test_all.sh activates test_basic.sh + test_configure.sh. + - test_basic.sh is better during active development, especially when you + gave additional options to configure script. + * split.c, qrspec.c, mqrspec.c, mask.c, mmask.c, qrencode.c, qrinput.c, + rsecc.c, qrencode.c: + - Fixed some warnings. (closing #89 and #102) + +2017.10.05 Kentaro Fukuchi <kentaro@fukuchi.org> + [4.0] + * tests/test_{mask,mmask,qrspec,mqrspec,split_urls,qrencode}.c: + - Removed or commented out unused functions. + - Command line option introduced for verbose debug information. + +2017.10.02 Kentaro Fukuchi <kentaro@fukuchi.org> + [4.0] + * bitstream.h, qrencode.c, qrencode_inner.h: + - Memory alignment improved. + * tests/test_qrencode.c: + - Error messages improved. + * tests/{common.h datachunk.h, decoder.h, rscode.h, rsecc_decoder.h}: + - Reserved macro names are replaced. + * bitstream.[ch]: + - Some variables' type changed from int to size_t. (closing #89 and + #102) + * tests/common.[ch], tests/test_split_url.c: + - Fixed some warnings. + * NEWS: + - Format fixes. + * tests/test_mask.c: + - Fixed some warnings. + * qrencode.h, qrinput.h, mqrspec.c: + - Comment format fixes. + * various files in tests: + - Fixed some warnings. + * tests/test_qrencode.c: + - Removed unused function. + * tests/test_qrinput.c: + - Added a new test function. + +2017.09.29 Kentaro Fukuchi <kentaro@fukuchi.org> + [4.0] + * README.md: + - Format fixes. + * rsecc.[ch]: + - Some variables' type changed from int to size_t. (closing #89 and + #102) + +2017.09.21 Kentaro Fukuchi <kentaro@fukuchi.org> + [4.0] + * qrencode.1.in, NEWS: + - Release date has been updated. + - Documentation updated. + * Version 4.0.0 has been released. + +2017.09.11 Kentaro Fukuchi <kentaro@fukuchi.org> + * qrenc.c: + - Read buffer is now allocated as a static array to avoid malloc(). + Suppresses memory leak warnings. (Thanks to @c-273) + * README.md: + - INSTALL and ACKNOWLEDGMENTS sections are updated. + * makeREADME.sh: + - Now it removes the attention line for github.com users. + * tests/test_qrenc.sh: + - Experimental test script for the command 'qrencode'. + - Dedicated to @c-273, who warned the possible memory leaks of qrencode. + (See #102) + * qrencode.spec.in, Makefile.am, configure.ac: + - SPEC file has been removed. (closes #105) + * Makefile.am: + - The generation rule for README has been improved. + [4.0] + * 4.0 branch has been started. + * README.md: + - Version number added to the 1st line. + - Fixed the URL to the badge of Travis CI. + [master] + * qrencode.[ch]: + - Symbol data representation of QRcode object has been slightly changed. + This change does not affect to most applications. + - If your application uses bits other than the LSB, read the comments of + QRCode class carefully. + * tests/test_qrencode.c: + - Modified correct pattern of a test referring non-LSB bits of QRCode. + * tests/view_qrcode.c: + - Now you can identify the feature of modules by color. + +2017.09.07 Kentaro Fukuchi <kentaro@fukuchi.org> + * *.[ch]: + - Copyright year updated for the next major update. + * tests/test_configure.sh: + - Added some progress messages. + * tests/test_all.sh: + - Added test_configure.sh to the list. + * Makefile.am, tests/Makefile.am: + - Added some EXTRA_DIST files. + - Moved some EXTRA_DIST files from Makefile.am to tests/Makefile.am. + * makeREADME.sh: + - Newly added. + * configure.ac, CMakeLists.txt, README, README.md: + - Bumped version to 4.0.0, preparing for major update. + * .travis.yml: + - Configuration improved. + * Makefile.am, README: + - Added a new rule to generate README from README.md. + - README is no longer needed in the source tree. + * .gitignore: + - Added 'CTestTestfile.cmake'. + - Added 'README' + * README.md: + - Added Katsumi Saito, the contributor of SPEC file, has been added to + the section of ACKNOWLEDGMENTS. We apologize for this lack of + acknowledgment. + +2017.09.06 Kentaro Fukuchi <kentaro@fukuchi.org> + * mqrspec.h: + - Documentation update. + * qrencode.[ch]: + - QRcode_clearCache() has been defined as a deprecated function for + backward compatibility. + * qrenc.c: + - Copyright year updated. + * NEWS, README, README.md: + - Documentation update. + * use/config.rpath: + - Updated to the newer version bundled with gettext-0.19.8.1. + * qrencode.1.in: + - Copyright year updated. + +2017.09.02 Kentaro Fukuchi <kentaro@fukuchi.org> + * configure.ac: + - Replaced AC_PROG_RANLIB with LT_INIT. + +2017.08.04 Kentaro Fukuchi <kentaro@fukuchi.org> + * CMakeLists.txt: + - Getopt.h is checked only by WITH_TOOLS. (merged #101) (Thanks to + @KangLin) + * README, README.md: + - ACKNOWLEDGMENTS has been updated. + +2017.03.15 Kentaro Fukuchi <kentaro@fukuchi.org> + * ChangeLog, NEWS, TODO: + - Typos fixed. (merged #95) (Thanks to @jwilk) + * README, README.md: + - ACKNOWLEDGMENTS has been updated. + * README, README.md, qrenc.c, qrencode.1.in, qrencode.spec.in: + - The URI to the primary site has been updated. (http->https) + * CMakeLists.txt: + - Add version of shared library. (merged #96) (Thanks to @vanillahsu) + +2017.02.05 Kentaro Fukuchi <kentaro@fukuchi.org> + * README, README.md: + - Added some notes to compile test programs. (closes #93) + * CMakeList.txt: + - Added BUILD_SHARED_LIBS option with MSVC export all. (merged #92) + (Thanks to @vilppuvuorinen) + +2017.02.03 Kentaro Fukuchi <kentaro@fukuchi.org> + * CMakeLists.txt, cmake/FIND*.cmake, tests/CMakeLists.txt: + - Merged #91. (Thanks to @aleksey-nikolaev) + - CMake support has been improved greatly. + * README, README.md: + - ACKNOWLEDGMENTS has been updated. + - Some text cleanups. + * tests/frame, .gitignore: + - Empty frame data "tests/frame" has been included in the source tree. + * .travis.yml + - Stopped creating empty frame data. + - Bug fix. + +2016.11.20 Kentaro Fukuchi <kentaro@fukuchi.org> + * tests/test_qrinput.c, tests/test_qrspec.c: + - Some warnings suppresed. + +2016.11.17 Kentaro Fukuchi <kentaro@fukuchi.org> + * CMakeLists.txt, tests/CMakeLists.txt, travis.yml, tests/common.h, + tests/decoder.c, .gitignore: + - Merged #85. (Thanks to @misery) + * NEWS: + - Release note for version 4 has been updated. + +2016.09.19 Kentaro Fukuchi <kentaro@fukuchi.org> + * qrenc.c, qrencode.c, split.c: + - Merged #82. (Thanks to @UniQP) + - Various code cleanups. + * *.h: + - Removed double underscores (__) from macro names in include guards. + (follows C99 standard) + * configure.ac, *.c: + - Renamed __STATIC macro to STATIC_IN_RELEASE. (follows C99 standard) + * qrencode.c: + - Removed unnecessary 'extern' from some functions. + +2016.09.18 Kentaro Fukuchi <kentaro@fukuchi.org> + * CMakeLists.txt: + - Merged #83. (Thanks to @misery) + - This allows CMake users building the library without configure script. + IF you are using incomplete UNIX-like environment and configure script + does not work as expected, try CMake. + * README, README.md: + - Added some notes about CMake. + +2016.05.18 Kentaro Fukuchi <kentaro@fukuchi.org> + * acinclude.m4: + - iconv.m4 has been updated to serial 19. + * configure.ac, Makefile.am, tests/Makefile.am: + - MinGW support has been improved. + * README, README.md: + - ACKNOWLEDGMENTS has been updated. + * qrencode.c: + - Memory leak bug fixed. (Closes #81. Thanks to @win32asm) + * Various code cleanups. (Merged #72. Thanks to @UniQP) + +2016.05.15 Kentaro Fukuchi <kentaro@fukuchi.org> + * configure.ac: + - Merged pull-request #80. (Thanks to @EckoEdc) + - Add LDFLAGS for mingw compilation. + +2016.04.02 Kentaro Fukuchi <kentaro@fukuchi.org> + * tests/common.h: + - Code refactoring. + - New debug functions have been added. + * tests/decoder.[ch], tests/test_monkey.c: + - QRcode_extractBits() has been extended. This will be used later. + * tests/decoder.[ch]: + - eccResult has been added to QRdata. + - Code refactoring. + * tests/decoder.[ch], tests/datachunk.[ch], tests/Makefile.am: + - Code refactoring. + +2016.03.30 Kentaro Fukuchi <kentaro@fukuchi.org> + * bitstream.[ch], tests/test_bitstream.c: + - Added new function BitStream_newWithBits() and tests for it. + * tests/decoder.[ch], tests/test_monkey.c: + - Code refactoring. + +2016.03.29 Kentaro Fukuchi <kentaro@fukuchi.org> + * tests/view_qrcode.c: + - Added mask=-2 mode for debug purpose. + * bitstream.c, qrencode.c: + - Incorrect bit padding has been fixed. (Thanks to Yuji Ueno) + * tests/test_bitstream.c, tests/test_qrencode.c: + - Incorrect bit padding has been fixed. + * README: + - ACKNOWLEDGMENTS has been updated. + * README.md: + - ACKNOWLEDGMENTS has been updated. + - Some missed contributors have been added to README.md. + +2016.02.21 Kentaro Fukuchi <kentaro@fukuchi.org> + * configure.ac, tests/common.h, tests/view_qrcode.c: + - Migrated from SDL 1.2 to 2.0. + * README, README.md: + - Improved the install instruction. (Thanks to Ronald Michaels) + +2015.11.04 Kentaro Fukuchi <kentaro@fukuchi.org> + * qrspec.h, mqrspec.h: + - Typo fix. (Thanks to @qianchenglenger) + * qrenc.c: + - Merged pull-request #74. (Thanks to @mgorny) + - Added support for UTF8i and ANSIUTF8i formats that provide reverse + mappings of UTF8 and ANSIUTF8 formats respective. This is useful for + black-on-white media. + * configure.ac, Makefile.am, qrenc.c, rsecc.c: + - Added new configure option "--without-png". (closes #70) + +2015.05.13 Kentaro Fukuchi <kentaro@fukuchi.org> + * mqrspec.c: + - Typo fix. + * README, README.md: + - Text format improved. + * NEWS: + - Slightly updated. + +2015.05.06 Kentaro Fukuchi <kentaro@fukuchi.org> + * qrenc.c: + - New option "--svg-path" has been added, that uses a single path + instead of multiple rectangles to draw the modules. + (cherry-picked from #41) (Thanks to @Oblomov) + * tests/test_qrenc.sh, tests/test_images/.gitignore: + - Added an unfinished test script for qrencode has been added. + +2015.05.05 Kentaro Fukuchi <kentaro@fukuchi.org> + * qrencode.1.in, qrenc.c: + - Usage improved. (closes #62) (Thanks to @minus7) + - Typo fix. (Thanks to Ian Sweet (@Isweet)) + * README, README.md: + - The list of contributors updated: '@' prefix added for github + usernames. + * qrenc.c: + - X Pixmap (XPM) support has been added. (closes #52) + (Thanks to @tklauser) + * qrspec.h, mqrspec.h, qrencode.h: + - empty descriptions of some @params are filled. + * rsecc.[ch], README: + - Short note about the credit has been improved. + * Some code cleanups. + +2015.05.04 Kentaro Fukuchi <kentaro@fukuchi.org> + * qrenc.c: + - Merge pull request #63 from tklauser/qrenc-array-overflow-fix + - qrenc: Fix array overrun in color_set (Thanks to @tklauser and + @win32asm) + * split.c: + - Merge pull request #67 from siggi-heltau/patch-1 + - The variable name "new" has been renamed to "newstring" because "new" + is a reserved word in C++. (Thanks to @siggi-heltau) + * qrenc.c: + - Added -r option to read input data from a file in addition to STDIN + and the command line. (cherry-picked from #68) + (Thanks to Robert Petersen) + - Typo fix. (cherry-picked from #68) (Thanks to Robert Petersen) + - long option "readin" has been changed to "read-from". + * qrencode.1.in: + - Updated the usage. + * README: + - Updated the list of contributors. + * tests/Makefile.am + - Added URI_testset.inc to EXTRA_DIST. + * .gitignore + - Added some patterns to ignore some generated files. (Thanks to + @tklauser, closes #64) + +2014.09.23 Kentaro FUKUCHI <kentaro@fukuchi.org> + * README, README.md: + - Some typo fixes. (Thanks to Danomi Manchego) + +2014.09.18 Kentaro FUKUCHI <kentaro@fukuchi.org> + * tests/view_qrcode.c: + - Rollbacked the previous change (6a4b2e3710b) around the main part. + * rsecc.c: + - Some code cleanups. + * tests/rsecc_decoder.[ch], tests/test_rs.c, Makefile.am: + - Syndrome checker has been added. + +2014.09.17 Kentaro FUKUCHI <kentaro@fukuchi.org> + * configure.ac: + - Added "-pthread" option to CFLAGS. (Thanks to Danomi Manchego) + * tests/Makefile.am: + - Removed explicit "-lpthread" which is not required anymore. + +2014.09.09 Kentaro FUKUCHI <kentaro@fukuchi.org> + * NEWS: + - Added an entry about 4.0.0. (not released yet) + * mask.[ch], tests/test_mask.c: + - Run length calculation has been slightly improved. + - Reduce malloc calls. + * qrspec.[ch], mqrspec.[ch]: + - Frame caches have been eliminated. It improves both memory efficiency + and performance... Wait, caches were completely meaningless? orz... + * qrencode.[ch]: + - QRcode_clearCache() has been eliminated. + * tests/prof_qrencode.c, tests/pthread_qrencode.c, tests/test_mask.c, + tests/test_mmask.c, tests/test_monkey.c, tests/test_mqrspec.c, + tests/test_qrencode.c, tests/test_qrspec.c: + - Removed cache clearing calls. + * qrencode.c: + - FrameFiller now allocated in stack, not heap. + * rsecc.c: + - Introduced mutex to avoid race condition. + +2014.09.08 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Added color support for EPS output. + +2014.08.18 Kentaro FUKUCHI <kentaro@fukuchi.org> + * configure.ac: + - Added new option "--enable-asan" that enables AddressSanitizer. + +2014.08.15 Kentaro FUKUCHI <kentaro@fukuchi.org> + * tests/view_qrcode.c: + - Version number check improved for Micro QR Code. + +2014.08.05 Kentaro FUKUCHI <kentaro@fukuchi.org> + * configure.ac, Makefile.am, tests/Makefile.am: + - Added some conditional flags for configuration/building process. + - HAVE_PNG and HAVE_SDL can be referred from both Makefile and program + code. + * tests/view_qrcode.c: + - Use SDL_WaitEvent() instead of SDL_PollEvent(). + * tests/common.h: + - Added show_QRcode() for testing purposes. (Thanks to Sunil Maganally) + * tests/*.c: + - main()'s arguments now correctly declared. + +2014.07.25 Kentaro FUKUCHI <kentaro@fukuchi.org> + * tests/URI_testset.inc, tests/test_split_urls.c, tests/Makefile.am, + .gitignore: + - A new test suite evaluating splitting efficiency has been added. + - Still undertrial. + +2014.07.24 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Code refactoring (QRinput_Struct_count has been added). + - And more code cleanups. + - Avoid to add a Structued-append chunk when only one symbol is + generated. (Thanks to Yoshimichi Inoue) + * tests/test_qrinput.c: + - New test has been added. + * qrinput.c, qrencode.1.in: + - Added new option, "verbose". + * tests/common.h: + - printQRinputStruct() has been added. + * rsecc.{c,h}: + - Copyright notice and credit has been corrected. + * README, README.md: + - ACKNOWLEDGMENTS updates. + [3.4] + - Bumped version to 3.4.4. + * Version 3.4.4 has been released. + +2014.07.08 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c, qrinput.c, tests/test_qrinput.c: + - Code cleanups. + - Some possible minor bugs has been fixed. + +2014.07.07 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Serious typo fix. + +2014.07.06 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c, qrencode.1.in: + - Added a new image type PNG32 (direct color mode). (Thanks to Greg Hart) + +2014.07.04 Kentaro FUKUCHI <kentaro@fukuchi.org> + * use/config.rpath: + - Updated to the newer version bundled with gettext-0.18.3.2. + * acinclude.m4: + - Added iconv.m4, lib-{link,ld,prefix}.m4 for Mac OS. + * autogen.sh: + - mkdir m4 if not exist. + * qrencode.h: + - Fixed some doxygen commands. + +2014.06.27 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c, qrencode.1.in: + - Merged pull-request #44. (Thanks to Antenore) + - Fixed some format issues. + +2014.06.22 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrencode.c: + - A memory leak bug has been fixed. (Thanks to @win32asm) + * bitstream.c: + - Check return value of BitStream_expand. (PR #46, Thanks to @tklauser) + +2014.02.14 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Minor documentation fix. + * qrenc.c: + - Error message improved. + +2014.02.09 Kentaro FUKUCHI <kentaro@fukuchi.org> + * .travis.yaml: + - Configuration file for Travis CI. (Thanks to Danil Dörrhöfer) + * configure.ac: + - Fixed some warnings. + +2014.01.15 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Merged pull request 78d44fd - commandline argument --help and -V is + printed to stdout, instead of stderr. + +2014.01.04 Kentaro FUKUCHI <kentaro@fukuchi.org> + * rsecc.[ch]: + - Code cleanups. + +2013.10.27 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Bug in QRinput_insertFNC1Header() has been fixed. (Thanks to David + Binderman) + * qrinput.c, test/decoder.[ch]: + - Code cleanup. + +2013.09.08 Kentaro FUKUCHI <kentaro@fukuchi.org> + * tests/test_qrencode.c: + - Small bug fix. + +2013.09.06 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - bzero() has been replaced with memset(). (Thanks to Gavin Andresen) + * qrspec.c, qrinput.c: + - QRspec_getMinimumVersion() now returns maximum version number for + excessive input, instead of -1. Closes #31. (Thanks to Danil + Dörrhöfer) + * tests/test_qrencode.c: + - New tests for excessive or maximum input have been added. + * tests/test_qrinput.c: + - A deprecatd test has been removed. + [reduce_malloc] + * bitstream.c: + - Minimum length of bit buffer has been extended to 128. In many cases + the library needs 128 bits at least to generate a symbol. + [master] + * merged reduce_malloc branch. + +2013.08.22 Kentaro FUKUCHI <kentaro@fukuchi.org> + * configure.ac: + - Avoid to use sdl-config. (Thanks to Heiko Becker) + +2013.08.15 Kentaro FUKUCHI <kentaro@fukuchi.org> + * rsecc.[ch], qrencode.c, tests/test_rc.c: + - Code cleanups and refactoring. + - Bug fix. + * configure.ac: + - Bumped version to 3.9.0, preparing for major update. + * qrenc.c: + - Copyright year in usage has been updated. + - Help message improved. + +2013.08.15 Kentaro FUKUCHI <kentaro@fukuchi.org> + * rsecc.[ch], rscode.[ch], Makefile.am, qrencode.c: + - Reed-Solomon error correction code has been completely rewritten. + - Phil Karn's code has been removed (moved to tests). + * tests/test_rs.c, tests/test_qrencode.c, tests/rscode.[ch], tests/Makefile.am: + - Test codes related to ECC have been updated. + - Phil Karn's code has been moved to tests, just for test purpose. + * tests/test_mqrspec.c: + - Code cleanup. + +2013.07.29 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4] + * configure.ac, README, NEWS: + - Bumped version to 3.4.3. + +2013.07.16 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - missing break in switch. (Thanks to ßlúèÇhîp) + * qrinput.c: + - missing/redundant breaks in some switch statements. + +2013.06.17 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Merged pull request #29. (Thanks to Daniel Dörrhöfer) + - Run length encoding has been made non-default. + - New option "--rle" has been instroduced to enable run length encoding + for SVG format. + +2013.03.30 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Renamed a variable ("index") to avoid compile-time warning. (Thanks to + Emmanuel Blot) + - Range check improved. + * autogen.sh: + - bug fix.(Thanks to Emmanuel Blot) + +2013.03.26 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Memory leak bug has been fixed. (Thanks to Hassan Hajji) + - Buffer overrun bug has been fixed. + - Code cleanups. + +2013.03.01 Kentaro FUKUCHI <kentaro@fukuchi.org> + * README, NEWS: + - Documentation update. + * Version 3.4.2 has been released. + +2013.02.26 Kentaro FUKUCHI <kentaro@fukuchi.org> + * split.c, tests/test_split.c: + - Applied Viona's bug fix patch. (Thanks to Viona) + - Additional switching cost between AN and Num mode has been included + correctly. + - Additional switching cost between 8 and AN/Num mode has been included + correctly. + - New test case has been added. + +2013.02.16 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4, master] + * configure.ac, README, NEWS: + - Bumped version to 3.4.2. + +2013.02.16 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Now it includes "string.h" by itself for libpng16. (Thanks to Petr) + +2012.11.30 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrencode.h + - Doxygen documents improved. + +2012.11.09 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Code cleanup. + +2012.11.08 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Memory leak bug has been fixed. (issue #24) (Thanks to chisj) + * qrencode.c: + - Incorrect bit extraction bug in QRcode_encodeMaskMQR() has been fixed. + (issue #25) (Thanks to vlad417) + * tests/test_qrencode.c: + - Added NUL checks for malloc-related bugs using failmalloc. + - Added a new test for issue #25. (Thanks to vlad417) + +2012.10.21 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Unnecessary "goto ABORT" eliminated. + +2012.10.17 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4] + * NEWS: + - Release note has been written. + * Version 3.4.1 has been released. + +2012.10.15 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4] + * configure.ac: + - HAVE_LIBPTHREAD was not correctly defined in config.h.in. + * tests/test_configure.sh: + - New test script checking autoconf-related scripts has been added. + * configure.ac, README, NEWS: + - Bumped version to 3.4.1. + +2012.10.15 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4] + * Version 3.4.0 has been released. + [master] + * Merged 3.4.0. + +2012.10.13 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4] + * qrencode.h: + - Documentation improved. + - Copyright year has been updated. + * Doxyfile: + - Rebased on a template from Doxygen 1.7.6.1. + +2012.10.09 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.4] + * configure.ac, README, NEWS: + - Bumped version to 3.4.0. + * qrencode.1.in: + - Added SVG option to --type. + * qrenc.c: + - Usage improved. + - Inkscape-friendly SVG output. + +2012.09.29 Kentaro FUKUCHI <kentaro@fukuchi.org> + [reduce_malloc] + * bstream.h: + - Added a new function "BitStream_reset()". + * qrinput.c: + - Reduced the use of dynamic memory allocation. + - Performance improved. + - Interfaces of QRinput_getBitStream() and QRinput_mergeBitStream() have + been changed. + +2012.09.25 Kentaro FUKUCHI <kentaro@fukuchi.org> + [reduce_malloc] + * qrinput.c, tests/qrinput.c: + - Reduced the use of dynamic memory allocation. + +2012.09.25 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Input validation improved. (Thanks to Yann Droneaud) + * README: + - Contributors list has been updated. + - Added a note about autogen.sh. + +2012.09.24 Kentaro FUKUCHI <kentaro@fukuchi.org> + * tests/test_bitstream.c: + - Added new test. + * tests/test_{monkey,qrspec}.c: + - Warnings suppressed. + [reduce_malloc] + * bitstream.[ch]: + - Reduced the use of dynamic memory allocation. + +2012.09.22 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Color palette support has been added. Currently PNG and SVG are + supported + * qrencode.1.in: + - "--foreground" and "--background" options have been added. + +2012.09.19 Kentaro FUKUCHI <kentaro@fukuchi.org> + * README: + - Contributors list has been updated. + * qrencode.1.in: + - Followed Unicode block elements patch. + +2012.09.18 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Merge pull request #19 from mezcalero/master (Unicode block elements + support). + +2012.09.13 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Set XML(SVG) declaration's 'standalone' to 'yes'. + +2012.09.03 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - A bug introduced in 'b3d5f7' has been reverted. (Thanks to Terry) + +2012.09.03 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Integrated David's SVG patch. + +2012.04.21 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Incorrect arguments order has been fixed. (Thank to Fred Steinhaeuser) + +2012.04.18 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.3] + * qrenc.c: + - EPS dot size bug has been fixed (closes: #12). + * Version 3.3.1 has been released. + +2012.04.11 Kentaro FUKUCHI <kentaro@fukuchi.org> + [master] + * qrenc.c: + - Paper size and margin are now set properly in SVG output. + +2012.04.10 Kentaro FUKUCHI <kentaro@fukuchi.org> + [master] + * Following fixes have been contributed by Yutaka Niibe. + * qrencode.1.in: + - "Hyphen-used-as-minus-sign" error has been fixed. + * configure.ac, libqrencode.pc.in, tests/Makefile.am: + - Explicit link to libpthread has been eliminated. + * qrenc.c: + - Pulled Repox's SVG patch (Pull request #10). + - Slightly simplified. + [3.3] + * README, configure.ac: + - Bumped version to 3.3.1. + +2012.04.01 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.3] + * qrenc.c: + - ASCII mode has been added. (Thanks to Ralf Ertzinger) + - Small code cleanups. + - ASCII mode now handles ".txt" suffix correctly. + * NEWS, README: + - Documentation updates. + * Version 3.3.0 has been released. + [master] + * Merged to 3.3.0. + +2012.03.31 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2] + * README, NEWS, configure.ac: + - Bumped version to 3.2.1. + * Version 3.2.1 has been released. + [3.3] + * qrenc.c: + - Copyright year has been updated. + +2012.03.30 Kentaro FUKUCHI <kentaro@fukuchi.org> + * libqrencode.pc.in : + - Replaced obsolete macro LIBPTHREAD with LIBS. (thx to gniibe) + * configure.ac: + - Checks $ac_cv_lib_pthread_pthread_mutex_init instead of + HAVE_LIBPTHREAD. (thx to gniibe) + +2012.02.28 Kentaro FUKUCHI <kentaro@fukuchi.org> + [master, 3.2.1] + * .gitignore: + - Added "tests/pthread_qrencode". + [3.3] + * 3.3 branch has been started. + - 3.2.1 has been canceled. + * configure.ac, README, NEWS: + - Version number changes. + +2012.01.31 Kentaro FUKUCHI <kentaro@fukuchi.org> + [master] + * Recent 3.2 branch has been merged into the master. + * qrenc.c: + - Quick bug fix introduced in 09b72eb3070a36461eb83c1ec5237e4855ee515b. + +2012.01.19 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2.1] + * configure.ac, qrencode.[hc], qrenc.c, tests/test_qrencode.c: + - QRcode_APIVersion() and QRcode_APIVersionString() have been added. + - New macro values {MAJOR,MINOR,MICRO}_VERSION have been introduced. + - New tests have been added. + * qrenc.c: + - Removed a useless storage class specifier from enum imageType. + [master, 3.2.1] + * Pulled moshen:write_ansi. + [3.2.1] + * tests/decoder.c: + - Bug fix. + * qrenc.c: + - Code refactoring. + - Now you can omit "-o -" for EPS and ANSI output. + - Default margin size has been rollbacked to 4 for ANSI(256). + * README: + - Added Colin (moshen@github) to ACKNOWLEDGMENTS. + - Added zapster's real name to ACKNOWLEDGMENTS. + +2011.12.12 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2.1] + * configure.ac, README: + - Bumped version to 3.2.1. + +2011.12.12 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c, qrencode.1.in: + - Usage updates. + +2011.12.11 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrenc.c: + - Pulled Zapster's EPS support patch. + - Some code cleanups. + +2011.11.26 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2.0] + * qrencode.1.in: + - "RESOURCES" section has been added. + * README: + - URL to the main web site updated. + * Version 3.2.0 has been released. + +2011.11.23 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2.0] + * qrencode.1.in: + - Added descriptions of "-d" and "-M". + +2011.11.3 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2.0] + * tests/view_qrcode.c: + - Messages improved. + * mmask.c: + - A bug in mask evaluation function has been eliminatd. + * tests/test_mmask.c: + - New test case has been added. + * qrenc.c: + - Micro QR Code support is now marked as "experimental" explicitly. + * tests/test_qrinput.c, tests/test_qrencode.c: + - Added some test cases. + +2011.10.23 Kentaro FUKUCHI <kentaro@fukuchi.org> + [3.2.0] + * 3.2 branch has been started. + * README, NEWS, configure.ac: + - Version number changes. + - Micro QR Code support is now marked as "experimental" explicitly. + +2011.10.23 Kentaro FUKUCHI <kentaro@fukuchi.org> + * mask.c, mmask.c, tests/common.h: + - Eliminated unused valiables. + * tests/test_qrencode.c: + - Some assertions added. + +2011.10.18 Kentaro FUKUCHI <kentaro@fukuchi.org> + * test/test_mask.c: + - To call QRspec_clearCache() at exit. + +2011.10.17 Kentaro FUKUCHI <kentaro@fukuchi.org> + * configure.ac: + - Now the latest PNG library is chosen when the configure script is + executed. + * Copyright year has been updated. + +2011.10.17 Kentaro FUKUCHI <kentaro@fukuchi.org> + * mask.c: + - Unneeded zero-clear has been eliminated from Mask_calcRunLength(). + - A rounding-down error in N4 calculation has been fixed. + (Thanks to Adam Shepherd) + * tests/test_mask.c: + - Fixed some test cases. + +2011.10.17 Kentaro FUKUCHI <kentaro@fukuchi.org> + * mask.c: + - A bug in N3 penalty calculation functoin has been fixed. + (Thanks to Adam Shepherd) + * mask.h, tests/test_mask.c: + - Test cases for Mask_calcN1N3() have been added. + - Wrong test cases have been corrected. + +2011.10.16 Kentaro FUKUCHI <kentaro@fukuchi.org> + * mask.[ch]: + - Mask_calcRunLength() has been refactored out from Mask_evaluateSymbol(). + * test/test_mask.c: + - New test code for Mask_calcRunLength has been added. + +2011.10.13 Kentaro FUKUCHI <kentaro@fukuchi.org> + * mask.[ch]: + - Mask_calcN2() has been refactored out from Mask_evaluateSymbol(). + * test/test_mask.c: + - New test code for Mask_calcN2 has been added. + * README: + - Added a URL to the git repository. + +2011.08.13 Kentaro FUKUCHI <kentaro@fukuchi.org> + * configure.ac: + - Added "AC_PROG_RANLIB" (bug report from dev66) + +2011.08.07 Kentaro FUKUCHI <kentaro@fukuchi.org> + * libqrencode.pc.in: + - Cflags has been set. (issue #2)(Thanks to ryo-on) + +2011.05.05 Kentaro FUKUCHI <kentaro@fukuchi.org> + * split.c: + - strdup() code has been added for non-POSIX environments. (Thanks to + Seth Sims) + * configure.ac: + - Added AC_CHECK_FUNC([strdup]) for non-POSIX environments. + - Now mudflapth is used instead of mudflap when pthread is enabled. + * *.c: + - '#include "config.h"' has been moved to the top of the code and + wrapped with #if HAVE_CONFIG_H - #endif. + +2011.04.06 Kentaro FUKUCHI <kentaro@fukuchi.org> + * qrinput.c: + - Initializaion was missed in QRinput_insertFNC1Header(). + +2011.02.09 Kentaro FUKUCHI <kentaro@fukuchi.org> + * tests/view_qrcode.c: + - "-h" had required an argument. + +2010.10.09 Kentaro FUKUCHI <kentaro@fukuchi.org> + * Copyright year and mail address were updated. + * README, qrencode.spec.in: + - The URL of qrencode's page has been updated. + * Makefile.am: + - Added ACLOCAL_AMFLAGS. + * use/config.rpath: + - Now explicitly included because required by AM_ICONV_LINK in + configure.ac. + +2010.02.03 Kentaro FUKUCHI <fukuchi@megaui.net> + [3.1.1] + * qrencode.c, README: + - Copyright year updates. + * Bumped version to 3.1.1. + * Version 3.1.1 has been released. + +2010.01.27 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrinput.c, qrencode.h: + - 8bit encoding improved. + - QRinput_encodeModeECI(), QRinput_appendECIheader(), + QRinput_estimateBitsModeECI() have been added. + * tests/test_qrinput.c: + - Some tests for ECI header have been added. + * qrinput.[ch]: + - STRUCTURE_HEADER_BITS was renamed to STRUCTURE_HEADER_SIZE. + - MODE_INDICATOR_SIZE has been added. + - QRinput_isSplittableMode() has been added. + * qrspec.c: + - QRspec_maximumWords() now returns 0 if the entry cannot be split. + - Now includes "qrinput.h" for QRinput_isSplittableMode(). + +2010.01.25 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.h: + - QR_MODE_{ECI,FNC1A,FNC1B} have been added to QRencodeMode. + * qrspec.h, mqrspec.h, qrinput.c: + - QRSPEC_MODEID_* and MQRSPEC_MODEID_* have been added, and hard coded + numbers were replaced with them. + * qrenc.c: + - Modified usage. + * qrinput.h: + - Added a new field to QRinput for FNC1 support. + * qrinput.c, qrencode.h: + - Added new functions to set FNC1 flag. + - FNC1 second position encoding now supported. + +2010.01.22 Kentaro FUKUCHI <fukuchi@megaui.net> + * tests/test_qrspec.c: + - Code cleanup. + * tests/decoder.[ch], tests/test_qrencode.c: + - Added tests for Micro QR Code. + +2010.01.20 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c: + - Bug fix. + * tests/decoder.[ch]: + - Code refactoring. + * tests/test_{qrencode,mask,monkey}.c, Makefile.am: + - New tests added. + * qrencode_inner.h: + - Typo fix. + * NEWS: + - Updated. + * qrinput.c: + - Possible memory errors fixed. + * configure.ac, tests/Makefile.am: + - Added iconv checks. + +2010.01.18 Kentaro FUKUCHI <fukuchi@megaui.net> + * configure.ac: + - Configuration cleanups. + * tests/Makefile.am: + - Wrong conditional branch fixed. + * tests/decoder.[ch], tests/Makefile.am: + - Decoding function has been added. + * tests/test_{qrinput,qrspec,qrencode}.c: + - New tests added. + +2010.01.16 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.[ch]: + - QRcode_encodeData{,MQR,Structured}() have been added. + * tests/test_qrencode.c: + - New test has been added. + +2009.11.27 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.h: + - Typo fixes. + +2009.11.06 Kentaro FUKUCHI <fukuchi@megaui.net> + * NEWS, README: + - Documents updated. + * qrspec.[ch], mqrspec.[ch]: + - *_clearCache were not thread safe. + - "Thread unsafe" warnings were removed. + * rscode.[ch] + - free_rs_cache was not thread safe. + - "Thread unsafe" warnings were removed. + +2009.09.28 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c: + - David's patch has been applied. (Thanks to David) + - New options '-d' and '--dpi' have been added. + - Typo fixes. + * tests/view_qrcode.c: + - Typo fixes. + +2009.06.08 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c: + - FrameFiller_nextMQR() has integrated to FrameFiller_next(). + - FrameFiller_new() now requires mqr flag. + * qrencode.[ch], tests/prof_qrencode.c, tests/test_{qrencode,monkey}.c: + - QRcode_clearCache() has been added. + * configure.ac, qrencode_inner.h, qrencode.c, mask.[ch], mmask.[ch], + qrinput.h, qrspec.c, tests/common.h: + - A macro WITH_TESTS has been introduced. + - "#ifdef __STATIC" has been replaced with "#ifdef __WITH_TESTS". + - Some definitions in qrencode_inner.h have been moved to appropriate + header files. + - Including config.h became mandatory for test programs. + * tests/pthread_qrencode.c, tests/Makefile.am: + - New test program has been added. + * rscode.c: + - config.h was not included. + * mask.c: + - Race condition problem has been solved. + +2009.06.06 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c, tests/view_qrcode.c: + - Experimental support of Micro QR Code has been implemented. + * qrencode.[ch]: + - QRinput_setVersionAndErrorCorrectionLevel() has been added. + * tests/common.h, tests/test_split.c: + - Code cleanups. + - printFrame() and printQRcode() have been added. + * tests/test_qrencode.c: + - Some tests have been added. + * qrspec.h, mqrspec.h, qrencode.h: + - Definitions of {MQR,QR}SPEC_VERSION_MAX are moved to qrencode.h. + * qrinput.c, qrencode.h, tests/test_qrencode.c: + - Size check has been removed from QRinput_convertData() for MQR. + - QRinput_convertData() throws ERANGE when the input is too large. + - QRinput_appendPadding*() throws ERANGE when the input is too large. + - As a result, QRencode_encodeString*() throws ERANGE in that cases. + - Some assertion checks of errno added to test_qrencode. + * Bumped version to 3.9.0. + - Next public release will be 4.0.0. + +2009.06.06 Kentaro FUKUCHI <fukuchi@megaui.net> + [3.1.0] + * Version 3.1.0 has been released. + +2009.06.05 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.h, qrencode_inner.h, tests/test_qrencode.c: + - FrameFiller_next() has improved. + - FrameFiller_nextMQR() has been added. + - FrameFiller_test() FrameFiller_testMQR() have been added. + - Tests of FrameFiller added and improved. + +2009.06.04 Kentaro FUKUCHI <fukuchi@megaui.net> + * Makefile.am: + - Dependency check was incorrect because of misconfiguration. + * mask.c, mmask.c: + - Error check has been added to {Mask,MMask}_makeMask(). + * mqrspec.[ch], qrinput.c: + - MQRspec_getDataLength() now returns in byte. + - MQRspec_getDataLengthBit() returns in bit instead. + * qrencode.[ch], qrencode_inner.h: + - QRencode_encodeStringMQR() and its 8bit version are added. + - QRcode_encodeMaskMQR() has been added. + +2009.06.01 Kentaro FUKUCHI <fukuchi@megaui.net> + * tests/prof_qrencode.c: + - Error check has been added. + * tests/common.h: + - Bug fixed. + * qrinput.c, qrencode.h: + - QRinput_Struct_appendInput() and QRinput_splitQRinputToStruct() now + checks mqr flag. + * tests/test_bitstream.c: + - New test of 4bit padding of _toByte(). + +2009.05.30 Kentaro FUKUCHI <fukuchi@megaui.net> + * configure.ac, libqrencode.pc.in: + - New option "--enable-thread-safety" has been added. This option is + enabled by default. + * rscode.c, qrspec.c: + - libqrencode has become thread-safe! (probably) + * tests/common.h: + - sprintfBin() removed, printBstream() added. + * qrinput.[ch], qrencode.[ch], mqrspec.c: + - Functions for Micro QR Code encoding have been added. + * tests/common.h: + - Utility functions improved. + * tests/*.c: + - Code cleanups. + - Tests for Micro QR Code added. + +2009.05.30 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrinput.c: + - padlen check was wrong in QRinput_appendPaddingBit(). + * tests/test_qrinput.c: + - Stop printing bstream->data. + - test_padding2() has been added. + +2009.05.21 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c, qrencode_inner.h: + - MQRraw_* has been implemented. + - Code cleanups. Struct QRRaw_code is slightly changed. + * tests/test_qrencode.c: + - Added new test. + +2009.05.20 Kentaro FUKUCHI <fukuchi@megaui.net> + * Merged from 3.1.0 branch. (rev 2248:HEAD) + * mqrspec.[ch], tests/create_mqr_frame_pattern.c: + - MQRspec_getEccSpec() has been deleted. + * tests/create_mqr_frame_pattern.c, tests/Makefile.am: + - Newly added. + * mask.[ch], tests/test_mask.c, qrencode_inner.h: + - Code cleanups. + - Unnecessary memcpy has been eliminated. + - New test program has been added. + * mmask.[ch], qrencode_inner.h, tests/test_mmask.c, Makefile.am, tests/Makefile.am: + - Mask module for Micro QR Code has been added. + +2009.05.20 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c, qrinput.c, qrencode.c: + - Some compile warnings cleared. + * qrencode.c, tests/test_qrencode.c: + - NULL check of an input arg has been added to + QRcode_encodeString8bit(). + - NULL check test and empty string test have been added for + QRcode_encodeString8bit(). + * qrinput.h, qrencode_inner.h, split.c: + - Copyright year updates. + * split.[ch]: + - Split_splitStringToQRinput() set errno EINVAL if input string is + NULL or empty. + - Documentation improved. + * qrenc.c: + - perror() is now used to show the details of some errors. + * qrencode.[ch]: + - Some functions now set errno appropriately. + - Typo fixes. + +2009.05.20 Kentaro FUKUCHI <fukuchi@megaui.net> + * tests/create_frame_pattern.c, tests/Makefile.am: + - New test tool "create_frame_pattern" has been added. + * tests/test_qrspec.c: + - test_alignment1() has been replaced with test_newframe(). + test_newframe() compares newly created frames with frame pattern + data created by create_frame_pattern. + * tests/frame, tests/Makefile.am: + - Pattern file "frame" has been added to EXTRA_DIST. + * mask.c: + - Very small improvement. Unnecessary malloc()s are reduced. + * tests/test_qrencode.c: + - Two new tests have been added. + * split.c: + - NULL check and string length check have been added. + * qrspec.c, tests/test_qrinput.c: + - Forgotten padding bits bug has been fixed. (enbugged at 2009.5.18) + - New test for the bug above has been added. + * qrspec.[ch], qrencode_inner.h: + - Some function becomes __STATIC and their declarations have been + moved to qrencode_inner.h. + * tests/prof_qrencode.c: + - Now liberates all heap at the end of the program. + +2009.05.19 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c, qrencode_inner.h: + - calloc() is now used to initialize rsblock. + - Number of malloc()s in RSblock_initBlock() has been integrated to + one malloc() in QRraw_new(). + * rscode.c: + - A very small code improvement. + * qrinput.[ch]: + - More return value checks. + - Code cleanups. + * tests/common.h, tests/test_{split,monkey,qrinput}.c: + - Tests improved. + * qrspec.[ch], tests/test_qrspec.c: + - Code cleanups. + - QRspec_rs{Data,Ecc}Length() have been added. + * tests/view_qrcode.c: + - Code cleanups. + - Disabled mask setting in structured mode. + * tests/common.h: + - assert_nothing() has been added. + * qrinput.c, qrencode.c, tests/test_*.c: + - Various *_free() now allow NULL pointer. (nothing performed) + * qrspec.[ch]: + - Alignment pattern is now put by QRspec_putAlignmentPattern(). + QRspec_getAlignmentPattern() and QRspec_freeAlignment() have been + removed. + +2009.05.18 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c: + - More return value checks. + * bitstream.c: + - BitStream_free() allows NULL pointer (nothing performed). + * qrinput.c: + - QRinput_List_freeEntry() and QRinput_free() allow NULL pointer. + - QRinput_createPaddingBit() has been replaced with + QRinput_appendPaddingBit(). + - QRinput_convertData() now sets errno to EINVAL when input is too + large. + - More return value checks. Mainly for ENOMEM error. + +2009.05.18 Kentaro FUKUCHI <fukuchi@megaui.net> + * Merged from 3.1.0 branch. + +2009.05.16 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.h: + - Indent improvement. + * Makefile.am: + - qrencode.spec has been added to EXTRA_DIST. + +2009.05.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrinput.c, qrencode.c, qrspe.c: + - More return value checks. Mainly for ENOMEM error. + * qrspec.[ch], qrencode.c, tests/test_qrspec.c: + - QRspec_getEccSpec() now accepts an int array instead to return + multiple values instead of returning dynamic allocated array. + * mask.c, rscode.c: + - More return value checks from malloc(). + * configure.ac: + - Added "--enable-mudflap" option. + * rscode.[ch]: + - Added free_rs_cache() for debug purpose. + * tests/test_{monkey,qrencode,rs}.c: + - Call free_rs_cache() at the end of the tests. + * qrencode.c: + - QRraw_new() and RSblock_init() have been improved. + - Eliminated unnecessary calls of init_rs(). + * autogen.sh, configure.ac: + - Darwin workarounds. + * tests/common.h, tests/test_bitstream.c: + - New tests have been added. + +2009.05.12 Kentaro FUKUCHI <fukuchi@megaui.net> + * bitstream.c: + - BitStream_toByte() had returned non-NULL for an empty BitStream. + * tests/test_bitstream.c: + - test_null() has been added. + * qrinput.c: + - A possible memory leak has been eliminated. It happened when a wrong + version number was given. + * tests/test_qriput.c: + - Memory leaks have been eliminated. + +2009.05.01 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 3.1.0. + +2009.04.30 Kentaro FUKUCHI <fukuchi@megaui.net> + * bitstream.[ch]: + - Internal representation of BitStream has been changed from + NUL-terminated string to unsigned char array. + * tests/common.h, tests/test_{bitstream,qrinput}.c: + - Some test sequences have been updated (see above). + +2009.03.25 Kentaro FUKUCHI <fukuchi@megaui.net> + * configure.ac: + - "--without-tests" has become default setting. + * bitstream.[ch]: + - Now functions strictly check return value from malloc() and return + error if it fails. + +2008.10.31 Kentaro FUKUCHI <fukuchi@megaui.net> + * tests/commo.h: + - __FUNCTION__ has been replaced with __func__, to follow the C99 + standard. + - The way of variadic macros has been changed, to follow the C99 + standard. + +2008.10.11 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode_inner.h: + - Now this header is called only by test programs. + * qrencode.c, qrencode_inner.h: + - Some definitions and declares written in qrencode_inner.h have been + moved into qrencode.c: + - QRraw_*() have been declared as __STATIC. + * mask.[ch], qrencode.c, qrencode_inner.h: + - Mask_makeMask() now requires QRecLevel. + - QRencode_writeFormatInformation() has been renamed and moved to + Mask_writeFormatInformation(), and become __STATIC. + * tests/*.c: + - Unneeded #include "qrencode_inner.h" have been removed. + +2008.10.11 Kentaro FUKUCHI <fukuchi@megaui.net> + * autogen.sh: + - Darwin workaround. + * configure.ac: + - Now config.h offers "__STATIC" macro becomes "static" when + "--without-tests" is specified. This macro is useful for functions + called from test programs but not from other library codes. + * qrinput.c: + - Very little performance improvement. + * mask.c: + - Code cleanups. + +2008.09.12 Kentaro FUKUCHI <fukuchi@megaui.net> + * tests/view_qrcode.c: + - Unused variable 'pitch' has been removed from draw_QRcode(). + +2008.06.03 Kentaro FUKUCHI <fukuchi@megaui.net> + * Merged to the main trunk. + +2008.06.01 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c: + - Now it does not show the full usage when unrecognized options are + given. + - When "--help" is given, it displays the long usage. + * Version 3.0.3 has been released. + +2008.05.26 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c, tests/view_qrcode.c: + - getopt_long_only() has been replaced with getopt_long() which is + widely available. (Thanks to Gavan Fantom) + - Now it accepts long options. + * qrencode.1.in: + - followed the above changes. + * Bumped version to 3.0.3. + +2008.05.18 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrspec.c: + - The bit order of "Version information" has been corrected. + (Thanks to Paul Janssesn) + * configure.ac, Makefile.am: + - The "--without-tests" has been added to the configure script. + * qrencode.spec.in: + - Uses "--without-tests". + * Version 3.0.2 has been released. + +2008.05.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * various files: + - Some compile-time warnings/erros with g++ have been fixed. + (Thanks to wangsai) + +2008.05.09 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c: + - Now qrencode writes an image file in binary mode for non-POSIX + platform, such as MS-Windows. (bug report from Paul Janssens) + * Makefile.am: + - tests/test_all.sh has been added. + * tests/test_all.sh: + - Now it exits immediately if any test fails. + * Version 3.0.1 has been released. + +2008.05.01 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.spec.in: + - Added the man page to the files section. + +2008.04.30 Kentaro FUKUCHI <fukuchi@megaui.net> + * Version 3.0.0 has been released. + +2008.04.23 Kentaro FUKUCHI <fukuchi@megaui.net> + * Version 3.0.0rc3 has been released. + - This will probably be the final release candidate, if all goes well. + +2008.04.23 Kentaro FUKUCHI <fukuchi@megaui.net> + * split.c: + - Split_identifyMode() now uses isdigit() and isalnum() macros. + * qrinput.c: + - Error checks have been improved. + * qrenc.c, tests/view_qrcode.c: + - Return value checks have been added. + - Structured-append encode with version 0 now returns error. + * qrencode.[ch]: + - QRencode_encodeStructuredInput() -> QRencode_encodeInputStructured() + (for consistency with other QRencode_encode*Structured() functions) + * mask.c: + - A code block never called has been eliminated. + +2008.04.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * Version 3.0.0rc2 has been released. + +2008.04.20 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.h: + - QR_MODE_NUL has been added to QRencodeMode. Basically it is used + only by Split_identifyMode(). + * qrinput.[ch], split.c: + - QRinput_identifyMode() has been moved to split.c, changed to static + and now needs a hint. + * split.c: + - Auto-splitting has been improved. + * qrinput.c: + - A memory leak has been fixed. + * configure.ac: + - The "--enable-gprof" and "--enable-gcov" options have been added. + * Makefile.am: + - man1_MANS has been moved into the "if BUILD_TOOLS - endif" block. + +2008.04.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * Version 3.0.0rc1 has been released. + +2008.04.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 3.0.0. + * qrencode.[ch]: + - QRcode_encodeInput() has changed the API. Previously it takes a + QRinput, version and level, but now it takes only a QRinput, because + QRinput holds the version and level in it. From 3.0.0, you should + set them by calling QRinput_setVersion() and + QRinput_setErrorCorrectionLevel(), or use QRinput_new2() to + instantiate a QRinput object. + +2008.04.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrspe.c: + - NULL check has been added. + * split.[ch]: + - API changed. + * qrencode.c: + - Arguments (version and level) are now checked in QRcode_encodeMask(). + Internal functions trust the arguments are valid. + - Error checks improved. + * qrinput.c: + - Error checks improved. + * qrencode.h: + - Documentation improvements. + +2008.04.13 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c, qrencode_inner.h, tests/view_qrcode.c: + - Changed API of QRcode_encodeMask(). + * qrencode.[ch], qrinput.[ch], split.[ch]: + - Some functions now set errno appropriately. + +2008.04.09 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.h, qrinput.c: + - QRinput_Struct_insertStructuredAppendHeaders() and + QRinput_insertStructuredAppendHeader now returns error, when the + input contains too many structured inputs. + * qrencode.c: + - QRcode_encodeInputToStructured() now returns NULL when + QRinput_splitQRinputToStruct() fails. + * tests/view_qrcode.c: + - Segmentation fault bug has been fixed. (see previous memo) + +2008.04.08 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrinput.c: + - Fixed a bug in QRinput_estimateBitStreamSizeOfEntry(). It could + overestimate the size. + * rscode.c: + - Optimized the order of the parameters equality test in init_rs(). + * qrspec.c, qrspec.h: + - Added QRspec_clearCache(). + * tests/test_estimatebit.c: + - Bug fixed in test_numbit3(). + +2008.04.07 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 2.1.0. + * Structured append is now supported (patches from Yusuke Mihara): + - Two new types, QRcode_List and QRinput_Struct, have been added. + - Following functions have been added: + - QRcode_encodeStructuredInput() + - QRcode_encodeStringStructured() + - QRcode_encodeString8bitStructured() + - Some functions to handle structured append symbols have been added. + See Doxygen-ized descriptions for the details. + * qrenc.c: + - "-S" option has been added for structured append. + * split.h: + - "extern" was dropped. + * qrinput.h, qrencode.h: + - Moved declarations of QRinput_{get,set}{Version,ErrorCorrectionLevel} + from qrinput.h to qrencode.h. Now they are publicly accessible. + * qrencode.h, qrinput.h, qrinput.c: + - Added QRinput_new2(). + - QRinput_newEntry(), QRinput_freeEntry have been renamed to + QRinput_List_newEntry(), QRinput_List_freeEntry(). + * split.c: + - Bug fix: Split_eat8() now eats at least 1 byte. Previously it could + produce a 0-length input entry. + +2008.01.23 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.1.in, Makefile.am, configure.ac: + - Manpage of qrencode has been added. + * qrenc.c, tests/view_qrcode.c: + - Usage message has been updated. + +2008.01.18 Kentaro FUKUCHI <fukuchi@megaui.net> + * split.c: + - Bug fixes. + * tests/test_split.c: + - Followed recent API changes. + - Added new test "test_toupper()". + * qrenc.c, tests/view_qrcode.c: + - Source-level compatibility has been improved. + - view_qrcode now accepts stdin like qrencode. + - Usage message has been updated/fixed. + * Copyright year has been updated. + +2008.01.16 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrinput.c, split.c: + - Case-sensitive mode becomes now default mode. + - Alphabet-Numeric mode now encodes only upper-case alphabet and + numeric characters. If "-i" option is given, split.c converts + lower-case characters to upper-case characters at first. + * qrenc.c, tests/view_qrcode.c: + - Case-sensitive mode becomes now default mode. + - Option "-i" has been added. + +2007.12.14 Kentaro FUKUCHI <fukuchi@megaui.net> + * tests/test_qrencode.c: + - New test has been added. + * tests/view_qrcode.c: + - Options supported. + - Default mask is now -1 (auto). + +2007.12.13 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.[ch]: + - QRcode_writeFormatInformation now returns a number of dark modules. + * mask.c: + - The mask evaluation function now writes format information before + evaluation. (Philippe Delcroix) + * split.[ch]: + - Case-sensitive mode has been added to QRcode_encodeString(). + - "-8" option has been added to qrenc.c. + - "-c" now encodes in improved case-sensitive mode. + * tests/test_{split,qrencode}.c: + - test_split*() have been moved to test_split.c. + +2007.12.10 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 2.0.0. + * Merged to main trunk. + * mask.[ch], split.[ch]: + - Masking functions and splitString functions are separated from + qrencode.c. + * mqrspec.[ch]: + - Specification of Micro QR code has been added, but not used yet. + +2007.03.24 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 1.0.2. + +2007.03.24 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode.c (QRcode_splitStringToQRinput): + - a small bug fix. (Thanks to NANKI Haruo) + * qrencode.h: + - "extern "C"" barrier has been added for C++. + * test/view_qrcode.c: + - a typo fix. + +2006.12.27 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 1.0.1. + +2006.12.27 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrenc.c, qrencode.[ch]: + - Added force 8-bit encoding mode. + * Makefile.am : + - Automake/Autoconf files have been added to dist-package. + +2006.12.17 Kentaro FUKUCHI <fukuchi@megaui.net> + * qrencode_inner.h, qrencode.c: + - Removed unused member variable "b2" from QRRawCode. + * configure.ac, Makefile.am, acinclude.m4: + - Better configuration of libpng. (now uses pkg-config correctly) + +2006.12.02 Kentaro FUKUCHI <fukuchi@megaui.net> + * Bumped version to 1.0.0. diff --git a/genqrcode/Doxyfile b/genqrcode/Doxyfile new file mode 100644 index 0000000000..a2a015120c --- /dev/null +++ b/genqrcode/Doxyfile @@ -0,0 +1,1781 @@ +# Doxyfile 1.7.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = QRencode + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "QR Code encoder" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = qrencode.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/genqrcode/Makefile.am b/genqrcode/Makefile.am new file mode 100644 index 0000000000..d631b6dfe6 --- /dev/null +++ b/genqrcode/Makefile.am @@ -0,0 +1,48 @@ +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS=-I m4 + +SUBDIRS = . + +if BUILD_TESTS +SUBDIRS += tests +endif + +lib_LTLIBRARIES = libqrencode.la + +libqrencode_la_SOURCES = qrencode.c qrencode_inner.h \ + qrinput.c qrinput.h \ + bitstream.c bitstream.h \ + qrspec.c qrspec.h \ + rsecc.c rsecc.h \ + split.c split.h \ + mask.c mask.h \ + mqrspec.c mqrspec.h \ + mmask.c mmask.h + +libqrencode_la_LDFLAGS = -version-number $(MAJOR_VERSION):$(MINOR_VERSION):$(MICRO_VERSION) + +include_HEADERS = qrencode.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libqrencode.pc +noinst_DATA = README +README_markdown_optional := $(wildcard README.md) +README: $(README_markdown_optional) + $(if $(README_markdown_optional), ./makeREADME.sh) + +EXTRA_DIST = libqrencode.pc.in autogen.sh configure.ac acinclude.m4 \ + Makefile.am tests/Makefile.am \ + qrencode.1.in Doxyfile \ + CMakeLists.txt cmake/FindIconv.cmake + +if BUILD_TOOLS +bin_PROGRAMS = qrencode +qrencode_SOURCES = qrenc.c +qrencode_CFLAGS = $(png_CFLAGS) +qrencode_LDADD = libqrencode.la $(png_LIBS) +man1_MANS = qrencode.1 +endif + +if MINGW +libqrencode_la_LDFLAGS += -no-undefined -avoid-version -Wl,--nxcompat -Wl,--dynamicbase +endif diff --git a/genqrcode/NEWS b/genqrcode/NEWS new file mode 100644 index 0000000000..aa9aba274d --- /dev/null +++ b/genqrcode/NEWS @@ -0,0 +1,360 @@ +libqrencode NEWS - Overview of changes +====================================== + +Version x.x.x (2020.xx.xx) +-------------------------- +* Command line tool "qrencode" has been improved: + * The effects of '--type' option's 'ASCII' and 'ASCIIi' have been swapped. + (Thanks to Yannick Schinko) +* Some minor bug fixes. (Thanks to Darsey Litzenberger and Edward E.) +* Some performance improvements. + + +Version 4.1.1 (2020.9.28) +------------------------- +* Some minor bugs in Micro QR Code generation have been fixed. + * The data capacity calculations are now correct. These bugs probably did not + affect the Micro QR Code generation. + + +Version 4.1.0 (2020.8.29) +------------------------- +* Command line tool "qrencode" has been improved: + * New option "--inline" has been added. (Thanks to @jp-bennett) + * New option "--strict-version" has been added. + * UTF8 mode now supports ANSI256 color. (Thanks to András Veres- + Szentkirályi) +* Micro QR Code no longer requires to specify the version number. +* 'make check' allows to run the test programs. (Thanks to Jan Tojnar) +* Some compile time warnings have been fixed. +* Various CMake support improvements. (Thanks to @mgorny and @sdf5) +* Some minor bug fixes. (Thanks to Lonnie Abelbeck and Frédéric Wang) +* Some documentation/manpage improvements. (Thanks to Dan Jacobson) +* Some performance improvements. (Thanks to @4061N and Mika Lindqvist) + +Release Note: +The internal representation of the output code has been slightly changed - +the second bit from LSB side now represents; 1:ECC bit / 0:data bit. +This change is only for debug purposes and does not affect user applications. + + +Version 4.0.2 (2018.6.6) +------------------------ +* Build script fixes. (Thanks to @mgorny) + + +Version 4.0.1 (2018.6.4) +------------------------ +* CMake support improved. +* New test scripts have been added. +* Some compile time warnings have been fixed. + + +Version 4.0.0 (2017.9.21) +------------------------- +* Memory efficiency has been improved. +* QRcode_clearCache() has been deprecated. +* Error correction code generating functions have been improved. +* Command line tool "qrencode" has been improved: + * XPM support. (Thanks to Tobias Klauser) + * PNG32 (direct color mode) support. (Thanks to Greg Hart) + * EPS output now supports foreground and background color. + * New options "-r" and "--svg-path" have been added. + (Thanks to Robert Petersen and @Oblomov) +* CMake support has been added. (optional) (Thanks to @misery) +* Various bug fixes. +* Various performance improvements. + +Release Note: +While the API has not been changed since the previous major release, we +incremented the major version number of libqrencode to 4 because the +implementation of the library has been largely changed. + +This release improves the performance and memory footprints of code generation. + +Now you can build libqrencode with CMake. + +If you build the test programs, please note that the required SDL version has +been changed from 1.2 to 2.0. + + +Version 3.4.4 (2014.7.24) +------------------------- +* Bug fix release. (Thanks to Yoshimichi Inoue) +* New option "--verbose" has been added to the command line tool. + +Release Note: +When only one symbol is generated in structured-append mode, the library had +inserted unnecessary chunk to the symbol and some QR Code readers fail to read +it. Now the library omits the chunk and generate a symbol identical to non- +structured symbol. + + +Version 3.4.3 (2013.8.12) +------------------------- +* New option "--rle" has been added to the command line tool (Thanks to Daniel + Dörrhöfer) +* Bug fixes. (Thanks to Hassan Hajji, Emmanuel Blot, and ßlúèÇhîp) + +Release Note: +This release contains a couple of bug fixes and a new minor feature of the +command line tool. Some minor bugs in the library have been fixed. + +Run Length Encoding (RLE) for SVG output decreases the size of the output file, +but it makes complicated to edit the image by SVG editors. A newly introduced +command line option "--rle" enables RLE. RLE will not be applied if it is not +given. + + +Version 3.4.2 (2013.3.1) +------------------------ +* Bug fix release. (Thanks to chisj, vlad417, Petr and Viona) + +Release Note: +Micro QR Code encoder had a bug that caused incorrect output (issue #25). Now +the bug has been fixed. Memory leak bug (#24) and insufficient string splitting +bug have been fixed. + + +Version 3.4.1 (2012.10.17) +-------------------------- +* Bug fix release. + +Release Note: +Mutual exclusion did not work correctly since 3.3.1. If your application uses +libqrencode in multithreaded environment, it is strongly recommended to update +it. + + +Version 3.4.0 (2012.10.15) +-------------------------- +* SVG, UTF8, and ANSIUTF8 output supports have been added to the command line + tool. (Thanks to Dan Storm, David Dahl, and Lennart Poettering) +* Colored QR Code support. +* Bug fixes. (Thanks to Terry Burton, Fred Steinhaeuser, and Yann Droneaud) + +Release Note: +Three new output format, SVG, UTF8, and ANSIUTF8 have been added to the command +line tool. UTF8 and ANSIUTF8 are another text art mode, using Unicode block +elements for high-resolution text output. Long-awaited colored QR code has been +introduced. Try "--foreground" and "--background" options to set the colors. +Currently PNG and SVG supports colored output. + + +Version 3.3.1 (2012.4.18) +------------------------- +* Bugs in command line tool, manual, configure script, and libtool files have + been fixed. (Thanks to Yutaka Niibe and Rob Ryan) + + +Version 3.3.0 (2012.4.1) +------------------------- +* EPS, ANSI, and ASCII text output supports have been added. + (Thanks to Zapster, Colin, and Ralf) +* QRcode_APIVersion() and QRcode_APIVersionString() have been added. + +Release Note: +Three new output format, EPS, ANSI, and ASCII text, have been added to the +command line tool. ANSI and ASCII mode ignore "-size" option. Give "-t ASCIIi" +to get an ASCII-mode symbol in inverted color. + +QRcode_APIVersion() is requested by Matthew Baker for better support of Python +ctypes binding. Check them out at https://code.google.com/p/libqrencode-ctypes/ + + +Version 3.2.1 (2012.4.1) +------------------------ +* Bugs in configure script and libtool file has been fixed. (Thanks to Yutaka + Niibe) + + +Version 3.2.0 (2011.11.26) +-------------------------- +* "--dpi" (or "-d") option has been added to qrencode. This option set DPI + information in an output PNG image. (Thanks to David Dahl) +* New option "--enable-thread-safety" has been added to the configure script + that makes the library thread-safe. It is enabled by default. +* QRcode_encodeData(), QRcode_encodeDataMQR, QRcode_encodeDataStructured() have + been added for binary data encoding including '\0'. +* Typo and bug fixes. +* Experimental Micro QR Code support has been added. +* "--micro" (or "-M") option for Micro QR Code has been added to qrencode. + (experimental) + +Release Note: +Binary data including '\0' is now supported. To encode a binary data, give "-8" +option to qrencode, and let qrencode obtain data via standard input like +"qrencode -8 -o output.png < binary". "--dpi" and "-d" are also added to embed +DPI information to PNG file. + +A bug in the mask pattern evaluation routine has been fixed. In some cases, +libqrencode may generate a different symbol from the one that was generated by +the prior libqrencode because of this bug fix, but the embedded data are not +affected. The symbols generated by the old libqrencode are valid. + +Experimental support of Micro QR Code encoder has been added. Some functions +(QRcode_*MQR()) have been added to the library. The command line tool generates +Micro QR Code when "--micro" or "-M" is given. + + +Version 3.1.1 (2010.2.3) +------------------------ +* A bug in the library has been fixed. + +Release Note: +Libqrecode had generated incorrect QR Code in some cases. Symbols larger than +version 5 (error correction level Q and H) were affected. In many cases this +bug did not cause serious damage thanks to the error correction mechanism, but +we highly recommend you to encode symbols again using this release. + + +Version 3.1.0 (2009.6.6) +------------------------ +* Various code cleanups and performance improves. +* Strict internal error checks have been added. +* "--without-tests" has become default setting. Specify "--with-tests" to + compile test programs. +* Some memory leak bugs have been fixed. + +Release Note: +This release focuses on the code cleanup and performance improve. Encoding time +has been improved, drastically in large symbols. Basically this update only +changes its internal code. The API is not changed, no need to recompile user +applications that includes only qrencode.h. If your application refers the +internal data representation (not recommended), see ChangeLog for further +information. + + +Version 3.0.3 (2008.6.1) +------------------------ +* Portability enhancement. (Thanks to Gavan Fantom) +* The command line tool "qrencode" now accepts long options. See the man page + for the detailed instruction. + +Release Note: +This release improves the portability of our command line tool "qrencode". +The library is not changed so that any applications using libqrencode are not +affected. + +From this release, qrencode accepts "long" options, such as "--help". See the +manpage for the detailed instructions. + +Qrencode now uses getopt_long() instead of getopt_long_only() which is not +available in some operating systems. If the getopt_long() is not provided or +the implementation of it is not compatible with GNU's one, please try +qrencode-3.0.3-gnulib, that contains the source code of the getopt_long(). +Gnulib version is a test release. If you feel happy with it, please let us know +and the future releases will include gnulib. + + +Version 3.0.2 (2008.5.18) +------------------------- +* Some compile-time warnings/errors with g++ have been fixed. + (Thanks to wangsai) +* The bit order of "Version information" has been corrected. + Symbols greater than version 6 were affected. (Thanks to Paul Janssesn) +* The "--without-tests" option has been added to the configure script. + + +Version 3.0.1 (2008.5.9) +------------------------ +* A bug fix for non-POSIX platform. (Thanks to Paul Janssens) +* The RPM spec file now packages the man page correctly. + + +Version 3.0.0 (2008.4.30) +------------------------- +* The interface of QRencode_encodeInput() has been changed. User applications + using it must be modified. +* Structured append support has been added. (patches from Yusuke Mihara) +* The "-S" option for structured append has been added to qrencode and + view_qrcode. +* Some functions now set errno to indicate errors. +* Some bug fixes. + +Release Note: +Now libqrencode supports "structured-append" of symbols. A large data set can +be split into multiple QR code symbols. The basic usage of structured-append +is not so different from the single symbol encoding: just call +QRcode_encodeStringStructured() or QRcode_encodeString8bitStructured() and +they return a list of symbols. Instead of giving a string, you can encode +an explicitly typed data. See the manual generated by Doxygen for the detailed +usage. + +Many thanks to Yusuke Mihara, who contributed a patch to add support of +structured-append to version 1.0.2. + +API changes: + +* Incompatible API changes: + - QRencode_encodeInput +* New types: + - QRinput_Struct + - QRcode_List +* New functions: + - QRinput_new2 + - QRinput_Struct_new + - QRinput_Struct_setParity + - QRinput_Struct_appendInput + - QRinput_Struct_free + - QRinput_Struct_insertStructuredAppendHeaders + - QRinput_splitQRinputToStruct + - QRcode_encodeStructuredInput + - QRcode_encodeStringStructured + - QRcode_encodeString8bitStructured + - QRcode_List_size + - QRcode_List_free +* Declarations moved to qrencode.h: + - QRinput_getErrorCorrectionLevel + - QRinput_setErrorCorrectionLevel + - QRinput_getVersion + - QRinput_setVersion + + +Version 2.0.0 (2008.1.24) +------------------------- +* "-i" option to ignore case distinctions has been added to qrencode and + view_qrcode. +* "-c" option (case-sensitive mode) of qrencode is now enabled by default and + has been improved. See details in Release Note section. +* "-8" option has been added to qrencode to encode whole data in 8-bit mode. +* tests/view_qrcode now accepts various options like qrencode. +* Man page has been added. +* Code cleanup. +* The mask evaluation bug has been fixed. (Philippe Delcroix) + +* API changes + - QRcode_encodeString() now receives case-sensitive flag. + - QRcode_encodeStringCase() has been removed. + - QRcode_encodeString8bit() has been added. + +Release Note: +Previously libqrencode encodes lower-case alphabet characters in Alphabet- +Numeric mode (upper-case alphabet and numeric) by default. According to the +specification of QR code, however, it is clearly claimed that Alphabet-Numeric +mode provides only upper-case alphabet (+ numeric and some symbol) characters. +Since this version, libqrencode distinguishes lower-case and upper-case of +alphabet characters by default. Because of that, "-c" option of qrencode +is now deprecated, and "-i" option has been added. By giving "-i", qrencode +converts lower-case characters to upper-case if possible, then encode a QR code +symbol. Please read qrencode.h for the details about API changes if you are +going to use this library. + +Many thanks to NANKI Haruo for his suggestions. + + +Version 1.0.2 (2007.03.24) +-------------------------- +* A small bug fix. (Thanks to NANKI Haruo) +* 'extern "C"' barrier has been added to qrencode.h. + + +Version 1.0.1 (2006.12.27) +-------------------------- +* Added "force 8-bit encoding mode". +* Configure script finds libpng's header correctly. + + +Version 1.0.0 (2006.12.12) +-------------------------- +* The first public release. diff --git a/genqrcode/README.md b/genqrcode/README.md new file mode 100644 index 0000000000..34f557aa9f --- /dev/null +++ b/genqrcode/README.md @@ -0,0 +1,235 @@ +# libqrencode - a fast and compact QR Code encoding library +[](https://github.com/fukuchi/libqrencode/actions) + +**Attention:** This repository contains the development version of libqrencode. See <https://fukuchi.org/works/qrencode/> for the official stable releases. At this moment, the latest stable release is version 4.1.1. + +GENERAL INFORMATION +=================== +Libqrencode is a fast and compact library for encoding data in a QR Code, +a 2D symbology that can be scanned by handy terminals such as a smartphone. +The capacity of QR Code is up to 7000 digits or 4000 characters and has high +robustness. + +Libqrencode accepts a string or a list of data chunks then encodes in a QR Code +symbol as a bitmap array. While other QR Code applications generate an image +file, using libqrencode allows applications to render QR Code symbols from raw +bitmap data directly. This library also contains a command-line utility outputs +QR Code images in various formats. + + +SPECIFICATION +============= +Libqrencode supports QR Code model 2, described in JIS (Japanese Industrial +Standards) X0510:2004 or ISO/IEC 18004. Most of features in the specification +are implemented such as: + +- Numeric, alphabet, Japanese kanji (Shift-JIS) or any 8 bit code can be + embedded +- Optimized encoding of a string +- Structured-append of symbols +- Micro QR Code (experimental) + +Currently the following features are not supported: + +- ECI and FNC1 mode +- QR Code model 1 (deprecated) + + +INSTALL +======= + +Requirements +------------ +While the command-line utility and some test programs use libpng or SDL 2.0, +the libqrencode library itself has no dependencies. You can skip compiling +tests and/or tools if you want not to install programs using SDL or PNG. + +Compile & install +----------------- +If there is no "configure" script in the source code directory, run +"autogen.sh" at first to generate it - this is mandatory if you downloaded the +source from GitHub. Some additional software is needed to complete this +process. For example, in Ubuntu, the following packages are needed: + +- autoconf +- automake +- autotools-dev +- libtool +- pkg-config +- libpng-dev + +You can skip this process if you have "configure" script already (typically +when you downloaded the source tarball from fukuchi.org.) + +Now you are ready to compile the library and tool. Type the following commands: + +``` +./configure +make +sudo make install +sudo ldconfig +``` + +This compiles and installs the library and header file to the appropriate +directories: by default, /usr/local/lib and /usr/local/include. You can change +the destination directory by passing some options to the configure script. +Run "./configure --help" to see the list of options. + +It also installs a command line tool "qrencode" to /usr/local/bin. If you want +not to build it, give "--without-tools" option to the configure script. + +If the configure script does not work well, try to use CMake. + +``` +cmake . +make +``` + +When you want to build the test programs, give "--with-tests" option to +configure, or "-DWITH\_TESTS=YES" to cmake. + +### Building libqrencode with vcpkg + +You can download and install libqrencode using the +[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: + +``` +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg integrate install +./vcpkg install libqrencode +``` + +The libqrencode port in vcpkg is kept up to date by Microsoft team members and +community contributors. If the version is out of date, please +[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the +vcpkg repository. + + +USAGE +===== +Basic usages of this library are written in the header file (qrencode.h). +You can generate a manual of the library by using Doxygen, or see + +https://fukuchi.org/works/qrencode/manual/index.html + + +WARNINGS +======== +The library is distributed WITHOUT ANY WARRANTY. + +Micro QR Code support is EXPERIMENTAL. + +Be careful to use the command line tool (qrencode) if it is used by a web +application (e.g. CGI script). For example, giving "-s" option with a large +number to qrencode may cause DoS. The parameters should be checked by the +application. + + +LICENSING INFORMATION +===================== +Copyright (C) 2006-2018, 2020 Kentaro Fukuchi + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 2.1 of the License, or any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this library; if not, write to the Free Software Foundation, Inc., 51 +Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +CONTACT +======= +Visit the homepage at: + +https://fukuchi.org/works/qrencode/ + +for new releases. The git repository is available at: + +https://github.com/fukuchi/libqrencode + +Please mail any bug reports, suggestions, comments, and questions to: + +Kentaro Fukuchi <kentaro@fukuchi.org> + +or submit issues to: + +https://github.com/fukuchi/libqrencode/issues + + +ACKNOWLEDGMENTS +=============== +QR Code is registered trademarks of DENSO WAVE INCORPORATED in JAPAN and other +countries. + +Reed-Solomon encoder included in this library is originally taken from FEC +library developed by Phil Karn (KA9Q) and distributed under the terms of the +GNU LGPL, then rewritten by Kentaro Fukuchi. +Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + +* NANKI Haruo - improved lower-case characters encoding +* Katsumi Saito - SPEC file +* Philippe Delcroix - improved mask evaluation +* Yusuke Mihara - structured-append support +* David Dahl - DPI and SVG support patch +* Adam Shepherd - bug fix patch of the mask evaluation +* Josef Eisl (@zapster) - EPS support patch +* Colin (@moshen) - ANSI support patch +* Ralf Ertzinger - ASCII support patch +* Yutaka Niibe (@gniibe)- various bug fix patches +* Dan Storm (@Repox) - SVG support patch +* Lennart Poettering (@mezcalero) + - improved text art patch +* Yann Droneaud - improved input validation patch +* Viona - bug fix patch for string splitting +* Daniel Dörrhöfer (@d4ndo) + - RLE option, some bug fixes, Travis configuration +* Greg Hart - PNG32 support patch +* @siggi-heltau - bug fix patch +* Tobias Klauser (@tklauser) + - bug fix patch, XPM support patch +* Robert Petersen (@ripetersen) + - added ability to read input data from a file +* @Oblomov - improved SVG support patch +* MichaÅ‚ Górny (@mgorny) + - reverse mappings of UTF8 and ANSIUTF8, build script + fixes +* @EckoEdc - MinGW support patch +* Sebastian Buchwald (@UniQP) + - Various code cleanups +* André Klitzing (@misery) + - CMake support +* Alexey Nikolaev (@aleksey-nikolaev) + - improved CMake support +* Vilppu Vuorinen (@vilppuvuorinen) + - improved CMake support +* @vanillahsu - bug fix patch +* @Ation - bug fix patch +* Jonathan Bennett - Added "--inline" option to qrencode +* András Veres-Szentkirályi + - ANSI256UTF8 support +* @sdf5 - improved CMake support +* Lonnie Abelbeck (@abelbeck) + - bug fix patch +* @4061N - performance improvement patch +* Rosen Penev (@neheb) - CMake bug fix patch +* Mika Lindqvist (@mtl1979) + - replacement for gettimeofday() for Windows. +* Darsey Litzenberger (@dlitz) and Edward E. (@cbrt64) + - fixed invalid XPM output +* Shigeyuki Hirai, Paul Janssens, wangsai, Gavan Fantom, Matthew Baker, + Rob Ryan, Fred Steinhaeuser, Terry Burton, @chisj, @vlad417, Petr, + Hassan Hajji, Emmanuel Blot, ßlúèÇhîp, Heiko Becker, Gavin Andresen, + David Binderman, @ralgozino, Sean McMurray, Vlad Bespalov (@win32asm), + Antenore Gatta, Yoshimichi Inoue, Sunil Maganally, Norman Gray, + Danomi Manchego, @minus7, Ian Sweet, @qianchenglenger, Ronald Michaels, + Yuji Ueno, Jakub Wilk, @KangLin, @c-273, @thebunnyrules, @NancyLi1013, + Frédéric Wang, Dan Jacobson, Jan Tojnar, @xiaoyur347, @charmander, + Yannick Schinko, @a6q + - bug report / suggestion / typo fixes diff --git a/genqrcode/TODO b/genqrcode/TODO new file mode 100644 index 0000000000..475abfa88f --- /dev/null +++ b/genqrcode/TODO @@ -0,0 +1,5 @@ +Micro QR code encoding is not tested well. + +Documents (not only the README, but also the manual of the library) needs +revision of grammar, spelling or to resolve ambiguity or incomplete descriptions. +Feel really free to send us your revision. diff --git a/genqrcode/acinclude.m4 b/genqrcode/acinclude.m4 new file mode 100644 index 0000000000..bfd896e613 --- /dev/null +++ b/genqrcode/acinclude.m4 @@ -0,0 +1,1391 @@ +# iconv.m4 serial 19 (gettext-0.18.2) +dnl Copyright (C) 2000-2002, 2007-2014 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include <stdlib.h> +#include <iconv.h> + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_func_iconv=yes]) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include <stdlib.h> +#include <iconv.h> + ]], + [[iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);]])], + [am_cv_lib_iconv=yes] + [am_cv_func_iconv=yes]) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ + dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, + dnl Solaris 10. + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include <iconv.h> +#include <string.h> + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + ]], + [[int result = 0; + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 1; + iconv_close (cd_utf8_to_88591); + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\263"; + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 2; + iconv_close (cd_ascii_to_88591); + } + } + /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304"; + static char buf[2] = { (char)0xDE, (char)0xAD }; + ICONV_CONST char *inptr = input; + size_t inbytesleft = 1; + char *outptr = buf; + size_t outbytesleft = 1; + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) + result |= 4; + iconv_close (cd_88591_to_utf8); + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + result |= 8; + iconv_close (cd_88591_to_utf8); + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + result |= 16; + return result; +]])], + [am_cv_func_iconv_works=yes], , + [case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac]) + test "$am_cv_func_iconv_works" = no || break + done + LIBS="$am_save_LIBS" + ]) + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + AC_DEFINE([HAVE_ICONV], [1], + [Define if you have the iconv() function and it works.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST([LIBICONV]) + AC_SUBST([LTLIBICONV]) +]) + +dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to +dnl avoid warnings like +dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". +dnl This is tricky because of the way 'aclocal' is implemented: +dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. +dnl Otherwise aclocal's initial scan pass would miss the macro definition. +dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. +dnl Otherwise aclocal would emit many "Use of uninitialized value $1" +dnl warnings. +m4_define([gl_iconv_AC_DEFUN], + m4_version_prereq([2.64], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [m4_ifdef([gl_00GNULIB], + [[AC_DEFUN_ONCE( + [$1], [$2])]], + [[AC_DEFUN( + [$1], [$2])]])])) +gl_iconv_AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL([am_cv_proto_iconv], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include <stdlib.h> +#include <iconv.h> +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif + ]], + [[]])], + [am_cv_proto_iconv_arg1=""], + [am_cv_proto_iconv_arg1="const"]) + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([ + $am_cv_proto_iconv]) + AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], + [Define as const if the declaration of iconv() needs const.]) + dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>. + m4_ifdef([gl_ICONV_H_DEFAULTS], + [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) + if test -n "$am_cv_proto_iconv_arg1"; then + ICONV_CONST="const" + fi + ]) + fi +]) +# lib-ld.m4 serial 6 +dnl Copyright (C) 1996-2003, 2009-2013 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Subroutines of libtool.m4, +dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid +dnl collision with libtool.m4. + +dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], +[# I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + acl_cv_prog_gnu_ld=yes + ;; +*) + acl_cv_prog_gnu_ld=no + ;; +esac]) +with_gnu_ld=$acl_cv_prog_gnu_ld +]) + +dnl From libtool-2.4. Sets the variable LD. +AC_DEFUN([AC_LIB_PROG_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld [default=no]])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` + while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL([acl_cv_path_LD], +[if test -z "$LD"; then + acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$acl_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$acl_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT([$LD]) +else + AC_MSG_RESULT([no]) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) +# lib-link.m4 serial 26 (gettext-0.18.2) +dnl Copyright (C) 2001-2013 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_PREREQ([2.54]) + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname +dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + pushdef([Name],[m4_translit([$1],[./+-], [____])]) + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + AC_SUBST([LIB]NAME[_PREFIX]) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + popdef([NAME]) + popdef([Name]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message]) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. The missing-message +dnl defaults to 'no' and may contain additional hints for the user. +dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} +dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname +dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + pushdef([Name],[m4_translit([$1],[./+-], [____])]) + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS, + dnl because these -l options might require -L options that are present in + dnl LIBS. -l options benefit only from the -L options listed before it. + dnl Otherwise, add it to the front of LIBS, because it may be a static + dnl library that depends on another static library that is present in LIBS. + dnl Static libraries benefit only from the static libraries listed after + dnl it. + case " $LIB[]NAME" in + *" -l"*) LIBS="$LIBS $LIB[]NAME" ;; + *) LIBS="$LIB[]NAME $LIBS" ;; + esac + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[$3]], [[$4]])], + [ac_cv_lib[]Name=yes], + [ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])']) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + LIB[]NAME[]_PREFIX= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + AC_SUBST([LIB]NAME[_PREFIX]) + popdef([NAME]) + popdef([Name]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl acl_libext, +dnl acl_shlibext, +dnl acl_libname_spec, +dnl acl_library_names_spec, +dnl acl_hardcode_libdir_flag_spec, +dnl acl_hardcode_libdir_separator, +dnl acl_hardcode_direct, +dnl acl_hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + dnl Tell automake >= 1.10 to complain if config.rpath is missing. + m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE([rpath], + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_FROMPACKAGE(name, package) +dnl declares that libname comes from the given package. The configure file +dnl will then not have a --with-libname-prefix option but a +dnl --with-package-prefix option. Several libraries can come from the same +dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar +dnl macro call that searches for libname. +AC_DEFUN([AC_LIB_FROMPACKAGE], +[ + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + define([acl_frompackage_]NAME, [$2]) + popdef([NAME]) + pushdef([PACK],[$2]) + pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + define([acl_libsinpackage_]PACKUP, + m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1]) + popdef([PACKUP]) + popdef([PACK]) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found +dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) + pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) + pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) + dnl Autoconf >= 2.61 supports dots in --with options. + pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_ARG_WITH(P_A_C_K[-prefix], +[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib + --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + LIB[]NAME[]_PREFIX= + dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been + dnl computed. So it has to be reset here. + HAVE_LIB[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + dnl The same code as in the loop below: + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + dnl First look for a shared library. + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + dnl Then look for a static library. + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$acl_hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = '$1'; then + LIB[]NAME[]_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi + popdef([P_A_C_K]) + popdef([PACKLIBS]) + popdef([PACKUP]) + popdef([PACK]) + popdef([NAME]) +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +dnl For those cases where a variable contains several -L and -l options +dnl referring to unknown libraries and directories, this macro determines the +dnl necessary additional linker options for the runtime path. +dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) +dnl sets LDADDVAR to linker options needed together with LIBSVALUE. +dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, +dnl otherwise linking without libtool is assumed. +AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], +[ + AC_REQUIRE([AC_LIB_RPATH]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + $1= + if test "$enable_rpath" != no; then + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode directories into the resulting + dnl binary. + rpathdirs= + next= + for opt in $2; do + if test -n "$next"; then + dir="$next" + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= + else + case $opt in + -L) next=yes ;; + -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` + dnl No need to hardcode the standard /usr/lib. + if test "X$dir" != "X/usr/$acl_libdirstem" \ + && test "X$dir" != "X/usr/$acl_libdirstem2"; then + rpathdirs="$rpathdirs $dir" + fi + next= ;; + *) next= ;; + esac + fi + done + if test "X$rpathdirs" != "X"; then + if test -n ""$3""; then + dnl libtool is used for linking. Use -R options. + for dir in $rpathdirs; do + $1="${$1}${$1:+ }-R$dir" + done + else + dnl The linker is used for linking directly. + if test -n "$acl_hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user + dnl must pass all path elements in one option. + alldirs= + for dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="$flag" + else + dnl The -rpath options are cumulative. + for dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + $1="${$1}${$1:+ }$flag" + done + fi + fi + fi + fi + fi + AC_SUBST([$1]) +]) +# lib-prefix.m4 serial 7 (gettext-0.18) +dnl Copyright (C) 2001-2005, 2008-2013 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_PREPARE_MULTILIB creates +dnl - a variable acl_libdirstem, containing the basename of the libdir, either +dnl "lib" or "lib64" or "lib/64", +dnl - a variable acl_libdirstem2, as a secondary possible value for +dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or +dnl "lib/amd64". +AC_DEFUN([AC_LIB_PREPARE_MULTILIB], +[ + dnl There is no formal standard regarding lib and lib64. + dnl On glibc systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine + dnl the compiler's default mode by looking at the compiler's library search + dnl path. If at least one of its elements ends in /lib64 or points to a + dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. + dnl Otherwise we use the default, namely "lib". + dnl On Solaris systems, the current practice is that on a system supporting + dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under + dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or + dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. + AC_REQUIRE([AC_CANONICAL_HOST]) + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment + dnl <http://docs.sun.com/app/docs/doc/816-5138/dev-env?l=en&a=view>. + dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." + dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the + dnl symlink is missing, so we set acl_libdirstem2 too. + AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], + [AC_EGREP_CPP([sixtyfour bits], [ +#ifdef _LP64 +sixtyfour bits +#endif + ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) + ]) + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" +]) diff --git a/genqrcode/autogen.sh b/genqrcode/autogen.sh new file mode 100755 index 0000000000..ab14d6c040 --- /dev/null +++ b/genqrcode/autogen.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +set -e + +if [ `uname -s` = Darwin ]; then + LIBTOOLIZE=glibtoolize +else + LIBTOOLIZE=libtoolize +fi + +ACLOCAL_OPT="" +if [ -d /usr/local/share/aclocal ]; then + ACLOCAL_OPT="-I /usr/local/share/aclocal" +elif [ -d /opt/local/share/aclocal ]; then + ACLOCAL_OPT="-I /opt/local/share/aclocal" +elif [ -d /usr/share/aclocal ]; then + ACLOCAL_OPT="-I /usr/share/aclocal" +fi + +if [ ! -d use ]; then + mkdir use +fi + +if [ ! -d m4 ]; then + mkdir m4 +fi + +autoheader + +aclocal $ACLOCAL_OPT + +$LIBTOOLIZE --automake --copy +automake --add-missing --copy + +autoconf diff --git a/genqrcode/bitstream.c b/genqrcode/bitstream.c new file mode 100644 index 0000000000..f620050dc6 --- /dev/null +++ b/genqrcode/bitstream.c @@ -0,0 +1,231 @@ +/* + * qrencode - QR Code encoder + * + * Binary sequence class. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "bitstream.h" + +#define DEFAULT_BUFSIZE (128) + +BitStream *BitStream_new(void) +{ + BitStream *bstream; + + bstream = (BitStream *)malloc(sizeof(BitStream)); + if(bstream == NULL) return NULL; + + bstream->length = 0; + bstream->data = (unsigned char *)malloc(DEFAULT_BUFSIZE); + if(bstream->data == NULL) { + free(bstream); + return NULL; + } + bstream->datasize = DEFAULT_BUFSIZE; + + return bstream; +} + +#ifdef WITH_TESTS +BitStream *BitStream_newWithBits(size_t size, unsigned char *bits) +{ + BitStream *bstream; + + if(size == 0) return BitStream_new(); + + bstream = (BitStream *)malloc(sizeof(BitStream)); + if(bstream == NULL) return NULL; + + bstream->data = (unsigned char *)malloc(size); + if(bstream->data == NULL) { + free(bstream); + return NULL; + } + + bstream->length = size; + bstream->datasize = size; + memcpy(bstream->data, bits, size); + + return bstream; +} +#endif + +static int BitStream_expand(BitStream *bstream) +{ + unsigned char *data; + + data = (unsigned char *)realloc(bstream->data, bstream->datasize * 2); + if(data == NULL) { + return -1; + } + + bstream->data = data; + bstream->datasize *= 2; + + return 0; +} + +static void BitStream_writeNum(unsigned char *dest, size_t bits, unsigned int num) +{ + unsigned int mask; + size_t i; + unsigned char *p; + + p = dest; + mask = 1U << (bits - 1); + for(i = 0; i < bits; i++) { + if(num & mask) { + *p = 1; + } else { + *p = 0; + } + p++; + mask = mask >> 1; + } +} + +static void BitStream_writeBytes(unsigned char *dest, size_t size, unsigned char *data) +{ + unsigned char mask; + size_t i, j; + unsigned char *p; + + p = dest; + for(i = 0; i < size; i++) { + mask = 0x80; + for(j = 0; j < 8; j++) { + if(data[i] & mask) { + *p = 1; + } else { + *p = 0; + } + p++; + mask = mask >> 1; + } + } +} + +int BitStream_append(BitStream *bstream, BitStream *arg) +{ + int ret; + + if(arg == NULL) { + return -1; + } + if(arg->length == 0) { + return 0; + } + + while(bstream->length + arg->length > bstream->datasize) { + ret = BitStream_expand(bstream); + if(ret < 0) return ret; + } + + memcpy(bstream->data + bstream->length, arg->data, arg->length); + bstream->length += arg->length; + + return 0; +} + +int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num) +{ + int ret; + + if(bits == 0) return 0; + + while(bstream->datasize - bstream->length < bits) { + ret = BitStream_expand(bstream); + if(ret < 0) return ret; + } + BitStream_writeNum(bstream->data + bstream->length, bits, num); + bstream->length += bits; + + return 0; +} + +int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data) +{ + int ret; + + if(size == 0) return 0; + + while(bstream->datasize - bstream->length < size * 8) { + ret = BitStream_expand(bstream); + if(ret < 0) return ret; + } + BitStream_writeBytes(bstream->data + bstream->length, size, data); + bstream->length += size * 8; + + return 0; +} + +unsigned char *BitStream_toByte(BitStream *bstream) +{ + size_t i, j, size, bytes, oddbits; + unsigned char *data, v; + unsigned char *p; + + size = BitStream_size(bstream); + if(size == 0) { + return NULL; + } + data = (unsigned char *)malloc((size + 7) / 8); + if(data == NULL) { + return NULL; + } + + bytes = size / 8; + + p = bstream->data; + for(i = 0; i < bytes; i++) { + v = 0; + for(j = 0; j < 8; j++) { + v = (unsigned char)(v << 1); + v |= *p; + p++; + } + data[i] = v; + } + oddbits = size & 7; + if(oddbits > 0) { + v = 0; + for(j = 0; j < oddbits; j++) { + v = (unsigned char)(v << 1); + v |= *p; + p++; + } + data[bytes] = (unsigned char)(v << (8 - oddbits)); + } + + return data; +} + +void BitStream_free(BitStream *bstream) +{ + if(bstream != NULL) { + free(bstream->data); + free(bstream); + } +} diff --git a/genqrcode/bitstream.h b/genqrcode/bitstream.h new file mode 100644 index 0000000000..70f3e1dfc5 --- /dev/null +++ b/genqrcode/bitstream.h @@ -0,0 +1,43 @@ +/* + * qrencode - QR Code encoder + * + * Binary sequence class. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +typedef struct { + size_t length; + size_t datasize; + unsigned char *data; +} BitStream; + +extern BitStream *BitStream_new(void); +#ifdef WITH_TESTS +extern BitStream *BitStream_newWithBits(size_t size, unsigned char *bits); +#endif +extern int BitStream_append(BitStream *bstream, BitStream *arg); +extern int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num); +extern int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data); +#define BitStream_size(__bstream__) (__bstream__->length) +#define BitStream_reset(__bstream__) (__bstream__->length = 0) +extern unsigned char *BitStream_toByte(BitStream *bstream); +extern void BitStream_free(BitStream *bstream); + +#endif /* BITSTREAM_H */ diff --git a/genqrcode/cmake/FindIconv.cmake b/genqrcode/cmake/FindIconv.cmake new file mode 100644 index 0000000000..fede82a093 --- /dev/null +++ b/genqrcode/cmake/FindIconv.cmake @@ -0,0 +1,115 @@ +include(CheckFunctionExists) + +set(_ICONV_SEARCHES) + +# Search ICONV_DIR first if it is set. +if(NOT ICONV_DIR AND ENV{ICONV_DIR}) + set(ICONV_DIR $ENV{ICONV_DIR}) +endif() + +if(ICONV_DIR) + set(_ICONV_DIR_SEARCH PATHS ${ICONV_DIR} NO_DEFAULT_PATH) + list(APPEND _ICONV_SEARCHES _ICONV_DIR_SEARCH) +endif() + +# Normal search. +set(_ICONV_SEARCH_NORMAL + PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Iconv;InstallPath]" + "$ENV{PROGRAMFILES}/iconv" + ENV CPATH + ENV C_INCLUDE_PATH + ENV CPLUS_INCLUDE_PATH + ENV LIBRARY_PATH) +list(APPEND _ICONV_SEARCHES _ICONV_SEARCH_NORMAL) + +set(ICONV_NAMES iconv iconv2 libiconv iconv64) +set(ICONV_NAMES_DEBUG iconvd iconv64d) + +# Try each search configuration. +foreach(search ${_ICONV_SEARCHES}) + find_path(ICONV_INCLUDE_DIR NAMES iconv.h ${${search}} PATH_SUFFIXES include) +endforeach() + +# Allow ICONV_LIBRARY to be set manually, as the location of the iconv library +if(NOT ICONV_LIBRARY) + foreach(search ${_ICONV_SEARCHES}) + find_library(ICONV_LIBRARY_RELEASE NAMES ${ICONV_NAMES} ${${search}} PATH_SUFFIXES lib) + find_library(ICONV_LIBRARY_DEBUG NAMES ${ICONV_NAMES_DEBUG} ${${search}} PATH_SUFFIXES lib) + endforeach() + + include(SelectLibraryConfigurations) + select_library_configurations(ICONV) +endif() + +unset(ICONV_NAMES) +unset(ICONV_NAMES_DEBUG) + +if(ICONV_INCLUDE_DIR AND EXISTS "${ICONV_INCLUDE_DIR}/iconv.h") + file(STRINGS "${ICONV_INCLUDE_DIR}/iconv.h" ICONV_H REGEX "^#define _LIBICONV_VERSION 0x([0-9]+)") + string(REGEX MATCH "q#define _LIBICONV_VERSION 0x([0-9][0-9])([0-9][0-9])?([0-9][0-9])?.*" temp_match "${ICONV_H}") + unset(temp_match) + if(CMAKE_MATCH_0) + set(ICONV_VERSION_MAJOR "${CMAKE_MATCH_1}") + set(ICONV_VERSION_MINOR "${CMAKE_MATCH_2}") + set(ICONV_VERSION_PATCH "${CMAKE_MATCH_3}") + string(REGEX REPLACE "0*([1-9][0-9]*).*" "\\1" ICONV_VERSION_MAJOR "${ICONV_VERSION_MAJOR}") + string(REGEX REPLACE "0*([1-9][0-9]*).*" "\\1" ICONV_VERSION_MINOR "${ICONV_VERSION_MINOR}") + string(REGEX REPLACE "0*([1-9][0-9]*).*" "\\1" ICONV_VERSION_PATCH "${ICONV_VERSION_PATCH}") + + set(ICONV_VERSION_STRING "${ICONV_VERSION_MAJOR}.${ICONV_VERSION_MINOR}") + if(ICONV_VERSION_PATCH) + set(ICONV_VERSION_STRING "${ICONV_VERSION_STRING}.${ICONV_VERSION_PATCH}") + endif() + endif() +endif() + +check_function_exists(iconv_open ICONV_IN_GLIBC) + +set(ICONV_FOUND_ANY FALSE) +if(ICONV_IN_GLIBC OR ICONV_LIBRARY) + set(ICONV_FOUND_ANY TRUE) +endif() + +# handle the QUIETLY and REQUIRED arguments and set ICONV_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ICONV + REQUIRED_VARS ICONV_FOUND_ANY ICONV_INCLUDE_DIR + VERSION_VAR ICONV_VERSION_STRING) + +mark_as_advanced(ICONV_LIBRARY ICONV_INCLUDE_DIR) + +if(NOT ICONV_FOUND) + return() +endif() + +set(ICONV_INCLUDE_DIRS ${ICONV_INCLUDE_DIR}) + +if(NOT ICONV_LIBRARIES) + set(ICONV_LIBRARIES ${ICONV_LIBRARY}) +endif() + +if(ICONV_LIBRARY AND NOT TARGET ICONV::ICONV) + add_library(ICONV::ICONV UNKNOWN IMPORTED) + set_target_properties(ICONV::ICONV PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ICONV_INCLUDE_DIRS}" + IMPORTED_LOCATION "${ICONV_LIBRARY}") + + if(ICONV_LIBRARY_RELEASE) + set_property(TARGET ICONV::ICONV APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(ICONV::ICONV PROPERTIES + IMPORTED_LOCATION_RELEASE "${ICONV_LIBRARY_RELEASE}") + endif() + + if(ICONV_LIBRARY_DEBUG) + set_property(TARGET ICONV::ICONV APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(ICONV::ICONV PROPERTIES + IMPORTED_LOCATION_DEBUG "${ICONV_LIBRARY_DEBUG}") + endif() +elseif(NOT TARGET ICONV::ICONV) + add_library(ICONV::ICONV INTERFACE IMPORTED) + set_target_properties(ICONV::ICONV PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ICONV_INCLUDE_DIRS}") +endif() diff --git a/genqrcode/configure.ac b/genqrcode/configure.ac new file mode 100644 index 0000000000..bc1d024d9b --- /dev/null +++ b/genqrcode/configure.ac @@ -0,0 +1,153 @@ +m4_define([__MAJOR_VERSION], [4])dnl +m4_define([__MINOR_VERSION], [1])dnl +m4_define([__MICRO_VERSION], [1])dnl +m4_define([__VERSION], [__MAJOR_VERSION.__MINOR_VERSION.__MICRO_VERSION])dnl +AC_INIT(QRencode, __VERSION) + +MAJOR_VERSION=__MAJOR_VERSION +MINOR_VERSION=__MINOR_VERSION +MICRO_VERSION=__MICRO_VERSION +AC_SUBST(MAJOR_VERSION) +AC_SUBST(MINOR_VERSION) +AC_SUBST(MICRO_VERSION) +AC_DEFINE_UNQUOTED([MAJOR_VERSION], [$MAJOR_VERSION], [Major version number]) +AC_DEFINE_UNQUOTED([MINOR_VERSION], [$MINOR_VERSION], [Minor version number]) +AC_DEFINE_UNQUOTED([MICRO_VERSION], [$MICRO_VERSION], [Micro version number]) + +AC_CONFIG_SRCDIR([qrencode.c]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_AUX_DIR(use) +AC_CONFIG_MACRO_DIR([m4]) +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE + +AC_DISABLE_STATIC +AC_C_CONST +AC_C_INLINE +AC_HEADER_STDC +AC_CHECK_HEADERS(sys/time.h) + +LT_INIT +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_INSTALL +AC_PROG_LIBTOOL +PKG_PROG_PKG_CONFIG + +case "${target}" in +*-*-mingw*) + mingw=yes +esac +AM_CONDITIONAL(MINGW, [test "x$mingw" = "xyes" ]) + +AC_CONFIG_FILES([Makefile libqrencode.pc tests/Makefile qrencode.1]) + +AC_CHECK_FUNCS([strdup]) + +dnl --enable-thread-safety +AC_ARG_ENABLE([thread-safety], [AS_HELP_STRING([--enable-thread-safety], [make the library thread-safe. [default=yes]])], + [], [enable_thread_safety=yes]) + +if test x$enable_thread_safety = xyes; then + AC_CHECK_LIB([pthread], [pthread_mutex_init], [AC_SUBST([LIBPTHREAD], [-lpthread])]) +fi +AM_CONDITIONAL([HAVE_LIBPTHREAD], [test "x$ac_cv_lib_pthread_pthread_mutex_init" = "xyes" ]) +# FIXME: isn't it able to integrate the followings to AC_CHECK_LIB? +if test x$ac_cv_lib_pthread_pthread_mutex_init = xyes ; then + AC_DEFINE([HAVE_LIBPTHREAD], [1], [Define to 1 if using pthread is enabled.]) + CFLAGS="$CFLAGS -pthread" +fi + +AC_ARG_WITH(png, + [AC_HELP_STRING([--without-png], + [disable PNG support])], + [with_png=$withval], [with_png=yes]) + +dnl --with-tools +AC_ARG_WITH([tools], [AS_HELP_STRING([--with-tools], [build utility tools [default=yes]])], + [build_tools=$withval], [build_tools=yes]) + +AM_CONDITIONAL(BUILD_TOOLS, [test "x$build_tools" = "xyes" ]) +if test x$build_tools = xyes && test x$with_png = xyes ; then + PKG_CHECK_MODULES(png, "libpng", [AC_DEFINE([HAVE_PNG], [1], [Define to 1 if using libpng is enabled.])], [AC_DEFINE([HAVE_PNG], [0])]) + if test "x$png_CFLAGS" = "x" && test x$with_png = xyes ; then + echo " +!!!!!!!!!! +LIBPNG is required to build the utility tools. Temporarily disabled. +!!!!!!!!!! +" + fi +fi +AM_CONDITIONAL(HAVE_PNG, [test "x$png_CFLAGS" != "x" ]) + +dnl --with-tests +AC_ARG_WITH([tests], [AS_HELP_STRING([--with-tests], [build tests [default=no]])], + [build_tests=$withval], [build_tests=no]) + +AM_CONDITIONAL(BUILD_TESTS, [test "x$build_tests" = "xyes" ]) +AH_VERBATIM([tests], +[/* Define to 'static' if no test programs will be compiled. */ +#define STATIC_IN_RELEASE static +#undef WITH_TESTS + ]) +if test x$build_tests = xyes ; then +echo "#define STATIC_IN_RELEASE" >>confdefs.h +echo "#define WITH_TESTS 1" >>confdefs.h +else +echo "#define STATIC_IN_RELEASE static" >>confdefs.h +echo "/* #undef WITH_TESTS */" >>confdefs.h +fi + +if test x$build_tests = xyes ; then + SDL_REQUIRED_VERSION=2.0.0 + PKG_CHECK_MODULES(SDL, [sdl2 >= $SDL_REQUIRED_VERSION], [AC_DEFINE([HAVE_SDL], [1], [Define to 1 if using SDL is enabled.])], [AC_DEFINE([HAVE_SDL], [0])]) + AM_ICONV_LINK +fi +AM_CONDITIONAL(HAVE_SDL, [test "x$SDL_CFLAGS" != "x" ]) + + +dnl --enable-gprof +AC_ARG_ENABLE([gprof], [AS_HELP_STRING([--enable-gprof], [generate extra code to write profile information suitable for gprof [default=no]])], + [], [enable_gprof=no]) + +if test x$enable_gprof = xyes; then + CFLAGS="$CFLAGS -g -pg" +fi + + +dnl --enable-gcov +AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], [generate extra code to write coverage information suitable for gcov [default=no]])], + [], [enable_gcov=no]) + +if test x$enable_gcov = xyes; then + CFLAGS="$CFLAGS --coverage" +fi + + +dnl --enable-asan +AC_ARG_ENABLE([asan], [AS_HELP_STRING([--enable-asan], [use AddressSanitizer [default=no]])], + [], [enable_asan=no]) + +if test x$enable_asan = xyes; then + CFLAGS="$CFLAGS -fsanitize=address -fno-omit-frame-pointer" + LDFLAGS="$LDFLAGS -fsanitize=address" +fi + + +dnl set CFLAGS +CFLAGS="-Wall $CFLAGS" + + +AC_OUTPUT + +echo "" +echo "Options used to compile and link:" +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo "" diff --git a/genqrcode/libqrencode.pc.in b/genqrcode/libqrencode.pc.in new file mode 100644 index 0000000000..ef6afbdf21 --- /dev/null +++ b/genqrcode/libqrencode.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libqrencode +Description: A QR Code encoding library +Version: @VERSION@ +Libs: -L${libdir} -lqrencode +Libs.private: @LIBPTHREAD@ +Cflags: -I${includedir} diff --git a/genqrcode/makeREADME.sh b/genqrcode/makeREADME.sh new file mode 100755 index 0000000000..d42e152d27 --- /dev/null +++ b/genqrcode/makeREADME.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +sed '/^```$/d +/badge\.svg/{N;d;} +/^\*\*Attention/d +s/DWITH\\_TESTS/DWITH_TESTS/ +1 { + s/^# // +} +' README.md > README diff --git a/genqrcode/mask.c b/genqrcode/mask.c new file mode 100644 index 0000000000..f812132033 --- /dev/null +++ b/genqrcode/mask.c @@ -0,0 +1,356 @@ +/* + * qrencode - QR Code encoder + * + * Masking. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <errno.h> + +#include "qrencode.h" +#include "qrspec.h" +#include "mask.h" + +STATIC_IN_RELEASE int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned int format; + unsigned char v; + int i; + int blacks = 0; + + format = QRspec_getFormatInfo(mask, level); + + for(i = 0; i < 8; i++) { + if(format & 1) { + blacks += 2; + v = 0x85; + } else { + v = 0x84; + } + frame[width * 8 + width - 1 - i] = v; + if(i < 6) { + frame[width * i + 8] = v; + } else { + frame[width * (i + 1) + 8] = v; + } + format= format >> 1; + } + for(i = 0; i < 7; i++) { + if(format & 1) { + blacks += 2; + v = 0x85; + } else { + v = 0x84; + } + frame[width * (width - 7 + i) + 8] = v; + if(i == 0) { + frame[width * 8 + 7] = v; + } else { + frame[width * 8 + 6 - i] = v; + } + format= format >> 1; + } + + return blacks; +} + +/** + * Penalty coefficients. + * See Section 8.8.2, p.45, JIS X0510:2004. + */ +#define N1 (3) +#define N2 (3) +#define N3 (40) +#define N4 (10) + +#define MASKMAKER(__exp__) \ + int x, y;\ + int b = 0;\ +\ + for(y = 0; y < width; y++) {\ + for(x = 0; x < width; x++) {\ + if(*s & 0x80) {\ + *d = *s;\ + } else {\ + *d = *s ^ ((__exp__) == 0);\ + }\ + b += (int)(*d & 1);\ + s++; d++;\ + }\ + }\ + return b; + +static int Mask_mask0(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((x+y)&1) +} + +static int Mask_mask1(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(y&1) +} + +static int Mask_mask2(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(x%3) +} + +static int Mask_mask3(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((x+y)%3) +} + +static int Mask_mask4(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(((y/2)+(x/3))&1) +} + +static int Mask_mask5(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(((x*y)&1)+(x*y)%3) +} + +static int Mask_mask6(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x*y)&1)+(x*y)%3)&1) +} + +static int Mask_mask7(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x*y)%3)+((x+y)&1))&1) +} + +#define maskNum (8) +typedef int MaskMaker(int, const unsigned char *, unsigned char *); +static MaskMaker *maskMakers[maskNum] = { + Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3, + Mask_mask4, Mask_mask5, Mask_mask6, Mask_mask7 +}; + +#ifdef WITH_TESTS +unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask) +{ + unsigned char *masked; + + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + + return masked; +} +#endif + +unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned char *masked; + + if(mask < 0 || mask >= maskNum) { + errno = EINVAL; + return NULL; + } + + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + Mask_writeFormatInformation(width, masked, mask, level); + + return masked; +} + + +//static int n1; +//static int n2; +//static int n3; +//static int n4; + +STATIC_IN_RELEASE int Mask_calcN1N3(int length, int *runLength) +{ + int i; + int penalty = 0; + int fact; + + for(i = 0; i < length; i++) { + if(runLength[i] >= 5) { + penalty += N1 + (runLength[i] - 5); + //n1 += N1 + (runLength[i] - 5); + } + if(i & 1) { + if(i >= 3 && i < length-2 && (runLength[i] % 3) == 0) { + fact = runLength[i] / 3; + if(runLength[i-2] == fact && + runLength[i-1] == fact && + runLength[i+1] == fact && + runLength[i+2] == fact) { + if(i == 3 || runLength[i-3] >= 4 * fact) { + penalty += N3; + //n3 += N3; + } else if(i+4 >= length || runLength[i+3] >= 4 * fact) { + penalty += N3; + //n3 += N3; + } + } + } + } + } + + return penalty; +} + +STATIC_IN_RELEASE int Mask_calcN2(int width, unsigned char *frame) +{ + int x, y; + unsigned char *p; + unsigned char b22, w22; + int penalty = 0; + + p = frame; + for(y = 1; y < width; y++) { + for(x = 1; x < width; x++) { + b22 = (p[0] & p[1] & p[width] & p[width+1]) & 1; + w22 = (p[0] | p[1] | p[width] | p[width+1]) & 1; + if(b22 != 0 || w22 == 0) { + penalty += N2; + } + p++; + } + p++; + } + + return penalty; +} + +STATIC_IN_RELEASE int Mask_calcRunLengthH(int width, unsigned char *frame, int *runLength) +{ + int head; + int i; + unsigned char prev; + + prev = frame[0]; + head = prev & 1; + if(head) { + runLength[0] = -1; + } + runLength[head] = 1; + + for(i = 1; i < width; i++) { + if((frame[i] ^ prev) & 1) { + head++; + runLength[head] = 1; + prev = frame[i]; + } else { + runLength[head]++; + } + } + + return head + 1; +} + +STATIC_IN_RELEASE int Mask_calcRunLengthV(int width, unsigned char *frame, int *runLength) +{ + int head; + int i; + unsigned char prev; + + prev = frame[0]; + head = prev & 1; + if(head) { + runLength[0] = -1; + } else { + } + runLength[head] = 1; + frame += width; + + for(i = 1; i < width; i++) { + if((*frame ^ prev) & 1) { + head++; + runLength[head] = 1; + prev = *frame; + } else { + runLength[head]++; + } + frame += width; + } + + return head + 1; +} + +STATIC_IN_RELEASE int Mask_evaluateSymbol(int width, unsigned char *frame) +{ + int x, y; + int penalty = 0; + int runLength[QRSPEC_WIDTH_MAX + 1]; + int length; + + penalty += Mask_calcN2(width, frame); + + for(y = 0; y < width; y++) { + length = Mask_calcRunLengthH(width, frame + y * width, runLength); + penalty += Mask_calcN1N3(length, runLength); + } + + for(x = 0; x < width; x++) { + length = Mask_calcRunLengthV(width, frame + x, runLength); + penalty += Mask_calcN1N3(length, runLength); + } + + return penalty; +} + +unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level) +{ + int i; + unsigned char *mask, *bestMask; + int minPenalty = INT_MAX; + int blacks; + int bratio; + int penalty; + int w2 = width * width; + + mask = (unsigned char *)malloc((size_t)w2); + if(mask == NULL) return NULL; + bestMask = (unsigned char *)malloc((size_t)w2); + if(bestMask == NULL) { + free(mask); + return NULL; + } + + for(i = 0; i < maskNum; i++) { +// n1 = n2 = n3 = n4 = 0; + penalty = 0; + blacks = maskMakers[i](width, frame, mask); + blacks += Mask_writeFormatInformation(width, mask, i, level); + bratio = (200 * blacks + w2) / w2 / 2; /* (int)(100*blacks/w2+0.5) */ + penalty = (abs(bratio - 50) / 5) * N4; +// n4 = penalty; + penalty += Mask_evaluateSymbol(width, mask); +// printf("(%d,%d,%d,%d)=%d\n", n1, n2, n3 ,n4, penalty); + if(penalty < minPenalty) { + minPenalty = penalty; + memcpy(bestMask, mask, (size_t)w2); + } + } + free(mask); + return bestMask; +} diff --git a/genqrcode/mask.h b/genqrcode/mask.h new file mode 100644 index 0000000000..169e64b2bb --- /dev/null +++ b/genqrcode/mask.h @@ -0,0 +1,38 @@ +/* + * qrencode - QR Code encoder + * + * Masking. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MASK_H +#define MASK_H + +extern unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level); + +#ifdef WITH_TESTS +extern int Mask_calcN2(int width, unsigned char *frame); +extern int Mask_calcN1N3(int length, int *runLength); +extern int Mask_calcRunLengthH(int width, unsigned char *frame, int *runLength); +extern int Mask_calcRunLengthV(int width, unsigned char *frame, int *runLength); +extern int Mask_evaluateSymbol(int width, unsigned char *frame); +extern int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask); +#endif + +#endif /* MASK_H */ diff --git a/genqrcode/mmask.c b/genqrcode/mmask.c new file mode 100644 index 0000000000..5f09a1e981 --- /dev/null +++ b/genqrcode/mmask.c @@ -0,0 +1,177 @@ +/* + * qrencode - QR Code encoder + * + * Masking for Micro QR Code. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <errno.h> + +#include "qrencode.h" +#include "mqrspec.h" +#include "mmask.h" + +STATIC_IN_RELEASE void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned int format; + unsigned char v; + int i; + + format = MQRspec_getFormatInfo(mask, version, level); + + for(i = 0; i < 8; i++) { + v = 0x84 | (format & 1); + frame[width * (i + 1) + 8] = v; + format = format >> 1; + } + for(i = 0; i < 7; i++) { + v = 0x84 | (format & 1); + frame[width * 8 + 7 - i] = v; + format = format >> 1; + } +} + +#define MASKMAKER(__exp__) \ + int x, y;\ +\ + for(y = 0; y < width; y++) {\ + for(x = 0; x < width; x++) {\ + if(*s & 0x80) {\ + *d = *s;\ + } else {\ + *d = *s ^ ((__exp__) == 0);\ + }\ + s++; d++;\ + }\ + } + +static void Mask_mask0(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(y&1) +} + +static void Mask_mask1(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(((y/2)+(x/3))&1) +} + +static void Mask_mask2(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x*y)&1)+(x*y)%3)&1) +} + +static void Mask_mask3(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x+y)&1)+((x*y)%3))&1) +} + +#define maskNum (4) +typedef void MaskMaker(int, const unsigned char *, unsigned char *); +static MaskMaker *maskMakers[maskNum] = { + Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3 +}; + +#ifdef WITH_TESTS +unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask) +{ + unsigned char *masked; + + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + + return masked; +} +#endif + +unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned char *masked; + int width; + + if(mask < 0 || mask >= maskNum) { + errno = EINVAL; + return NULL; + } + + width = MQRspec_getWidth(version); + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + MMask_writeFormatInformation(version, width, masked, mask, level); + + return masked; +} + +STATIC_IN_RELEASE int MMask_evaluateSymbol(int width, unsigned char *frame) +{ + int x, y; + unsigned char *p; + int sum1 = 0, sum2 = 0; + + p = frame + width * (width - 1); + for(x = 1; x < width; x++) { + sum1 += (p[x] & 1); + } + + p = frame + width * 2 - 1; + for(y = 1; y < width; y++) { + sum2 += (*p & 1); + p += width; + } + + return (sum1 <= sum2)?(sum1 * 16 + sum2):(sum2 * 16 + sum1); +} + +unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level) +{ + int i; + unsigned char *mask, *bestMask; + int maxScore = 0; + int score; + int width; + + width = MQRspec_getWidth(version); + + mask = (unsigned char *)malloc((size_t)(width * width)); + if(mask == NULL) return NULL; + bestMask = NULL; + + for(i = 0; i < maskNum; i++) { + score = 0; + maskMakers[i](width, frame, mask); + MMask_writeFormatInformation(version, width, mask, i, level); + score = MMask_evaluateSymbol(width, mask); + if(score > maxScore) { + maxScore = score; + free(bestMask); + bestMask = mask; + mask = (unsigned char *)malloc((size_t)(width * width)); + if(mask == NULL) break; + } + } + free(mask); + return bestMask; +} diff --git a/genqrcode/mmask.h b/genqrcode/mmask.h new file mode 100644 index 0000000000..56a58cd2d7 --- /dev/null +++ b/genqrcode/mmask.h @@ -0,0 +1,34 @@ +/* + * qrencode - QR Code encoder + * + * Masking for Micro QR Code. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MMASK_H +#define MMASK_H + +extern unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level); + +#ifdef WITH_TESTS +extern int MMask_evaluateSymbol(int width, unsigned char *frame); +extern void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask); +#endif + +#endif /* MMASK_H */ diff --git a/genqrcode/mqrspec.c b/genqrcode/mqrspec.c new file mode 100644 index 0000000000..6dbc9e11a2 --- /dev/null +++ b/genqrcode/mqrspec.c @@ -0,0 +1,232 @@ +/* + * qrencode - QR Code encoder + * + * Micro QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "mqrspec.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +typedef struct { + int width; ///< Edge length of the symbol + int ec[4]; ///< Number of ECC code (bytes) +} MQRspec_Capacity; + +/** + * Table of the capacity of symbols + * See Table 1 (p.106) and Table 8 (p.113) of Appendix 1, JIS X0510:2004. + */ +static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = { + { 0, {0, 0, 0, 0}}, + { 11, {2, 0, 0, 0}}, + { 13, {5, 6, 0, 0}}, + { 15, {6, 8, 0, 0}}, + { 17, {8, 10, 14, 0}} +}; + +int MQRspec_getDataLengthBit(int version, QRecLevel level) +{ + int w; + int ecc; + + w = mqrspecCapacity[version].width - 1; + ecc = mqrspecCapacity[version].ec[level]; + if(ecc == 0) return 0; + return w * w - 64 - ecc * 8; +} + +int MQRspec_getDataLength(int version, QRecLevel level) +{ + return (MQRspec_getDataLengthBit(version, level) + 4) / 8; +} + +int MQRspec_getECCLength(int version, QRecLevel level) +{ + return mqrspecCapacity[version].ec[level]; +} + +int MQRspec_getWidth(int version) +{ + return mqrspecCapacity[version].width; +} + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * See Table 3 (p.107) of Appendix 1, JIS X0510:2004. + */ +static const int lengthTableBits[4][4] = { + { 3, 4, 5, 6}, + { 0, 3, 4, 5}, + { 0, 0, 4, 5}, + { 0, 0, 3, 4} +}; + +int MQRspec_lengthIndicator(QRencodeMode mode, int version) +{ + return lengthTableBits[mode][version - 1]; +} + +int MQRspec_maximumWords(QRencodeMode mode, int version) +{ + int bits; + int words; + + bits = lengthTableBits[mode][version - 1]; + words = (1 << bits) - 1; + if(mode == QR_MODE_KANJI) { + words *= 2; // the number of bytes is required + } + + return words; +} + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/* See calcFormatInfo in tests/test_mqrspec.c */ +static const unsigned int formatInfo[4][8] = { + {0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3}, + {0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4}, + {0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d}, + {0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba} +}; + +/* See Table 10 of Appendix 1. (p.115) */ +static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = { + {-1, -1, -1}, + { 0, -1, -1}, + { 1, 2, -1}, + { 3, 4, -1}, + { 5, 6, 7} +}; + +unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level) +{ + int type; + + if(mask < 0 || mask > 3) return 0; + if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0; + if(level == QR_ECLEVEL_H) return 0; + type = typeTable[version][level]; + if(type < 0) return 0; + + return formatInfo[mask][type]; +} + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Put a finder pattern. + * @param frame destination frame data + * @param width frame width + * @param ox,oy upper-left coordinate of the pattern + */ +static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + }; + int x, y; + const unsigned char *s; + + frame += oy * width + ox; + s = finder; + for(y = 0; y < 7; y++) { + for(x = 0; x < 7; x++) { + frame[x] = s[x]; + } + frame += width; + s += 7; + } +} + +static unsigned char *MQRspec_createFrame(int version) +{ + unsigned char *frame, *p, *q; + int width; + int x, y; + + width = mqrspecCapacity[version].width; + frame = (unsigned char *)malloc((size_t)(width * width)); + if(frame == NULL) return NULL; + + memset(frame, 0, (size_t)(width * width)); + /* Finder pattern */ + putFinderPattern(frame, width, 0, 0); + /* Separator */ + p = frame; + for(y = 0; y < 7; y++) { + p[7] = 0xc0; + p += width; + } + memset(frame + width * 7, 0xc0, 8); + /* Mask format information area */ + memset(frame + width * 8 + 1, 0x84, 8); + p = frame + width + 8; + for(y = 0; y < 7; y++) { + *p = 0x84; + p += width; + } + /* Timing pattern */ + p = frame + 8; + q = frame + width * 8; + for(x = 1; x < width-7; x++) { + *p = 0x90 | (x & 1); + *q = 0x90 | (x & 1); + p++; + q += width; + } + + return frame; +} + +unsigned char *MQRspec_newFrame(int version) +{ + if(version < 1 || version > MQRSPEC_VERSION_MAX) return NULL; + + return MQRspec_createFrame(version); +} diff --git a/genqrcode/mqrspec.h b/genqrcode/mqrspec.h new file mode 100644 index 0000000000..c8ab425080 --- /dev/null +++ b/genqrcode/mqrspec.h @@ -0,0 +1,150 @@ +/* + * qrencode - QR Code encoder + * + * Micro QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MQRSPEC_H +#define MQRSPEC_H + +#include "qrencode.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +/** + * Maximum width of a symbol + */ +#define MQRSPEC_WIDTH_MAX 17 + +/** + * Return maximum data code length (bits) for the version. + * @param version version of the symbol + * @param level error correction level + * @return maximum size (bits) + */ +extern int MQRspec_getDataLengthBit(int version, QRecLevel level); + +/** + * Return maximum data code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return maximum size (bytes) + */ +extern int MQRspec_getDataLength(int version, QRecLevel level); + +/** + * Return maximum error correction code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return ECC size (bytes) + */ +extern int MQRspec_getECCLength(int version, QRecLevel level); + +/** + * Return a version number that satisfies the input code length. + * @param size input code length (byte) + * @param level error correction level + * @return version number + */ +extern int MQRspec_getMinimumVersion(int size, QRecLevel level); + +/** + * Return the width of the symbol for the version. + * @param version version of the symbol + * @return width + */ +extern int MQRspec_getWidth(int version); + +/** + * Return the numer of remainder bits. + * @param version version of the symbol + * @return number of remainder bits + */ +extern int MQRspec_getRemainder(int version); + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * Return the size of length indicator for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the size of the appropriate length indicator (bits). + */ +extern int MQRspec_lengthIndicator(QRencodeMode mode, int version); + +/** + * Return the maximum length for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the maximum length (bytes) + */ +extern int MQRspec_maximumWords(QRencodeMode mode, int version); + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Return BCH encoded version information pattern that is used for the symbol + * of version 7 or greater. Use lower 18 bits. + * @param version vesion of the symbol + * @return BCH encoded version information pattern + */ +extern unsigned int MQRspec_getVersionPattern(int version); + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/** + * Return BCH encoded format information pattern. + * @param mask mask number + * @param version version of the symbol + * @param level error correction level + * @return BCH encoded format information pattern + */ +extern unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level); + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Return a copy of initialized frame. + * @param version version of the symbol + * @return Array of unsigned char. You can free it by free(). + */ +extern unsigned char *MQRspec_newFrame(int version); + +/****************************************************************************** + * Mode indicator + *****************************************************************************/ + +/** + * Mode indicator. See Table 2 in Appendix 1 of JIS X0510:2004, p.107. + */ +#define MQRSPEC_MODEID_NUM 0 +#define MQRSPEC_MODEID_AN 1 +#define MQRSPEC_MODEID_8 2 +#define MQRSPEC_MODEID_KANJI 3 + +#endif /* MQRSPEC_H */ diff --git a/genqrcode/qrenc.c b/genqrcode/qrenc.c new file mode 100644 index 0000000000..1ce8c989b0 --- /dev/null +++ b/genqrcode/qrenc.c @@ -0,0 +1,1451 @@ +/** + * qrencode - QR Code encoder + * + * QR Code encoding tool + * Copyright (C) 2006-2018, 2020 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#if HAVE_PNG +#include <png.h> +#endif + +#include "qrencode.h" + +#define INCHES_PER_METER (100.0/2.54) + +static int casesensitive = 1; +static int eightbit = 0; +static int version = 0; +static int size = 3; +static int margin = -1; +static int dpi = 72; +static int structured = 0; +static int rle = 0; +static int svg_path = 0; +static int micro = 0; +static int inline_svg = 0; +static int strict_versioning = 0; +static QRecLevel level = QR_ECLEVEL_L; +static QRencodeMode hint = QR_MODE_8; +static unsigned char fg_color[4] = {0, 0, 0, 255}; +static unsigned char bg_color[4] = {255, 255, 255, 255}; + +static int verbose = 0; + +enum imageType { + PNG_TYPE, + PNG32_TYPE, + EPS_TYPE, + SVG_TYPE, + XPM_TYPE, + ANSI_TYPE, + ANSI256_TYPE, + ASCII_TYPE, + ASCIIi_TYPE, + UTF8_TYPE, + ANSIUTF8_TYPE, + ANSI256UTF8_TYPE, + UTF8i_TYPE, + ANSIUTF8i_TYPE +}; + +static enum imageType image_type = PNG_TYPE; + +static const struct option options[] = { + {"help" , no_argument , NULL, 'h'}, + {"output" , required_argument, NULL, 'o'}, + {"read-from" , required_argument, NULL, 'r'}, + {"level" , required_argument, NULL, 'l'}, + {"size" , required_argument, NULL, 's'}, + {"symversion" , required_argument, NULL, 'v'}, + {"margin" , required_argument, NULL, 'm'}, + {"dpi" , required_argument, NULL, 'd'}, + {"type" , required_argument, NULL, 't'}, + {"structured" , no_argument , NULL, 'S'}, + {"kanji" , no_argument , NULL, 'k'}, + {"casesensitive" , no_argument , NULL, 'c'}, + {"ignorecase" , no_argument , NULL, 'i'}, + {"8bit" , no_argument , NULL, '8'}, + {"micro" , no_argument , NULL, 'M'}, + {"rle" , no_argument , &rle, 1}, + {"svg-path" , no_argument , &svg_path, 1}, + {"inline" , no_argument , &inline_svg, 1}, + {"strict-version", no_argument , &strict_versioning, 1}, + {"foreground" , required_argument, NULL, 'f'}, + {"background" , required_argument, NULL, 'b'}, + {"version" , no_argument , NULL, 'V'}, + {"verbose" , no_argument , &verbose, 1}, + {NULL, 0, NULL, 0} +}; + +static char *optstring = "ho:r:l:s:v:m:d:t:Skci8MV"; + +static void usage(int help, int longopt, int status) +{ + FILE *out = status ? stderr : stdout; + fprintf(out, +"qrencode version %s\n" +"Copyright (C) 2006-2018, 2020 Kentaro Fukuchi\n", QRcode_APIVersionString()); + if(help) { + if(longopt) { + fprintf(out, +"Usage: qrencode [-o FILENAME] [OPTION]... [STRING]\n" +"Encode input data in a QR Code and save as a PNG or EPS image.\n\n" +" -h, --help display the help message. -h displays only the help of short\n" +" options.\n\n" +" -o FILENAME, --output=FILENAME\n" +" write image to FILENAME. If '-' is specified, the result\n" +" will be output to standard output. If -S is given, structured\n" +" symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n" +" (suffix is removed from FILENAME, if specified)\n\n" +" -r FILENAME, --read-from=FILENAME\n" +" read input data from FILENAME.\n\n" +" -s NUMBER, --size=NUMBER\n" +" specify module size in dots (pixels). (default=3)\n\n" +" -l {LMQH}, --level={LMQH}\n" +" specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n\n" +" -v NUMBER, --symversion=NUMBER\n" +" specify the minimum version of the symbol. See SYMBOL VERSIONS\n" +" for more information. (default=auto)\n\n" +" -m NUMBER, --margin=NUMBER\n" +" specify the width of the margins. (default=4 (2 for Micro QR)))\n\n" +" -d NUMBER, --dpi=NUMBER\n" +" specify the DPI of the generated PNG. (default=72)\n\n" +" -t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8},\n" +" --type={PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8}\n" +" specify the type of the generated image. (default=PNG)\n" +" If ASCII*, UTF8*, or ANSI* is specified, the image will be disp-\n" +" layed in the terminal by using text characters instead of gene-\n" +" rating an image file. If the name of the type is followed by\n" +" 'i', the light/dark character will be reversed.\n" +" -S, --structured\n" +" make structured symbols. Version must be specified with '-v'.\n\n" +" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n" +" -c, --casesensitive\n" +" encode lower-case alphabet characters in 8-bit mode. (default)\n\n" +" -i, --ignorecase\n" +" ignore case distinctions and use only upper-case characters.\n\n" +" -8, --8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n" +" -M, --micro encode in a Micro QR Code.\n\n" +" --rle enable run-length encoding for SVG.\n\n" +" --svg-path\n" +" use single path to draw modules for SVG.\n\n" +" --inline only useful for SVG output, generates an SVG without the XML tag.\n\n" +" --foreground=RRGGBB[AA]\n" +" --background=RRGGBB[AA]\n" +" specify foreground/background color in hexadecimal notation.\n" +" 6-digit (RGB) or 8-digit (RGBA) form are supported.\n" +" Color output support available only in PNG, EPS and SVG.\n\n" +" --strict-version\n" +" disable automatic version number adjustment. If the input data is\n" +" too large for the specified version, the program exits with the\n" +" code of 1.\n\n" +" -V, --version\n" +" display the version number and copyrights of the qrencode.\n\n" +" --verbose\n" +" display verbose information to stderr.\n\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n\n" +"SYMBOL VERSIONS\n" +" The symbol versions of QR Code range from Version 1 to Version\n" +" 40. Each version has a different module configuration or number\n" +" of modules, ranging from Version 1 (21 x 21 modules) up to\n" +" Version 40 (177 x 177 modules). Each higher version number\n" +" comprises 4 additional modules per side by default. See\n" +" https://www.qrcode.com/en/about/version.html for a detailed\n" +" version list.\n" + + ); + } else { + fprintf(out, +"Usage: qrencode [-o FILENAME] [OPTION]... [STRING]\n" +"Encode input data in a QR Code and save as a PNG or EPS image.\n\n" +" -h display this message.\n" +" --help display the usage of long options.\n" +" -o FILENAME write image to FILENAME. If '-' is specified, the result\n" +" will be output to standard output. If -S is given, structured\n" +" symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n" +" (suffix is removed from FILENAME, if specified)\n" +" -r FILENAME read input data from FILENAME.\n" +" -s NUMBER specify module size in dots (pixels). (default=3)\n" +" -l {LMQH} specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n" +" -v NUMBER specify the minimum version of the symbol. (default=auto)\n" +" -m NUMBER specify the width of the margins. (default=4 (2 for Micro))\n" +" -d NUMBER specify the DPI of the generated PNG. (default=72)\n" +" -t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8}\n" +" specify the type of the generated image. (default=PNG)\n" +" -S make structured symbols. Version number must be specified with '-v'.\n" +" -k assume that the input text contains kanji (shift-jis).\n" +" -c encode lower-case alphabet characters in 8-bit mode. (default)\n" +" -i ignore case distinctions and use only upper-case characters.\n" +" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n" +" -M encode in a Micro QR Code.\n" +" -V display the version number and copyrights of the qrencode.\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n\n" +" Try \"qrencode --help\" for more options.\n" + ); + } + } +} + +static int color_set(unsigned char color[4], const char *value) +{ + int len = (int)strlen(value); + int i, count; + unsigned int col[4]; + if(len == 6) { + count = sscanf(value, "%02x%02x%02x%n", &col[0], &col[1], &col[2], &len); + if(count < 3 || len != 6) { + return -1; + } + for(i = 0; i < 3; i++) { + color[i] = (unsigned char)col[i]; + } + color[3] = 255; + } else if(len == 8) { + count = sscanf(value, "%02x%02x%02x%02x%n", &col[0], &col[1], &col[2], &col[3], &len); + if(count < 4 || len != 8) { + return -1; + } + for(i = 0; i < 4; i++) { + color[i] = (unsigned char)col[i]; + } + } else { + return -1; + } + return 0; +} + +#define MAX_DATA_SIZE (7090 * 2) /* timed by the safty factor 2 */ +static unsigned char data_buffer[MAX_DATA_SIZE]; +static unsigned char *readFile(FILE *fp, int *length) +{ + int ret; + + ret = (int)fread(data_buffer, 1, MAX_DATA_SIZE, fp); + if(ret == 0) { + fprintf(stderr, "No input data.\n"); + exit(EXIT_FAILURE); + } + if(feof(fp) == 0) { + fprintf(stderr, "Input data is too large.\n"); + exit(EXIT_FAILURE); + } + + data_buffer[ret] = '\0'; + *length = ret; + + return data_buffer; +} + +static FILE *openFile(const char *outfile) +{ + FILE *fp; + + if(outfile == NULL || (outfile[0] == '-' && outfile[1] == '\0')) { + fp = stdout; + } else { + fp = fopen(outfile, "wb"); + if(fp == NULL) { + fprintf(stderr, "Failed to create file: %s\n", outfile); + perror(NULL); + exit(EXIT_FAILURE); + } + } + + return fp; +} + +#if HAVE_PNG +static void fillRow(unsigned char *row, int num, const unsigned char color[]) +{ + int i; + + for(i = 0; i < num; i++) { + memcpy(row, color, 4); + row += 4; + } +} +#endif + +static int writePNG(const QRcode *qrcode, const char *outfile, enum imageType type) +{ +#if HAVE_PNG + static FILE *fp; // avoid clobbering by setjmp. + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette = NULL; + png_byte alpha_values[2]; + unsigned char *row, *p, *q; + int x, y, xx, yy, bit; + int realwidth; + + realwidth = (qrcode->width + margin * 2) * size; + if(type == PNG_TYPE) { + row = (unsigned char *)malloc((size_t)((realwidth + 7) / 8)); + } else if(type == PNG32_TYPE) { + row = (unsigned char *)malloc((size_t)realwidth * 4); + } else { + fprintf(stderr, "Internal error.\n"); + exit(EXIT_FAILURE); + } + if(row == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + if(outfile[0] == '-' && outfile[1] == '\0') { + fp = stdout; + } else { + fp = fopen(outfile, "wb"); + if(fp == NULL) { + fprintf(stderr, "Failed to create file: %s\n", outfile); + perror(NULL); + exit(EXIT_FAILURE); + } + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(png_ptr == NULL) { + fprintf(stderr, "Failed to initialize PNG writer.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if(info_ptr == NULL) { + fprintf(stderr, "Failed to initialize PNG write.\n"); + exit(EXIT_FAILURE); + } + + if(setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fprintf(stderr, "Failed to write PNG image.\n"); + exit(EXIT_FAILURE); + } + + if(type == PNG_TYPE) { + palette = (png_colorp) malloc(sizeof(png_color) * 2); + if(palette == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + palette[0].red = fg_color[0]; + palette[0].green = fg_color[1]; + palette[0].blue = fg_color[2]; + palette[1].red = bg_color[0]; + palette[1].green = bg_color[1]; + palette[1].blue = bg_color[2]; + alpha_values[0] = fg_color[3]; + alpha_values[1] = bg_color[3]; + png_set_PLTE(png_ptr, info_ptr, palette, 2); + png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL); + } + + png_init_io(png_ptr, fp); + if(type == PNG_TYPE) { + png_set_IHDR(png_ptr, info_ptr, + (unsigned int)realwidth, (unsigned int)realwidth, + 1, + PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + } else { + png_set_IHDR(png_ptr, info_ptr, + (unsigned int)realwidth, (unsigned int)realwidth, + 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + } + png_set_pHYs(png_ptr, info_ptr, + (png_uint_32)(dpi * INCHES_PER_METER), + (png_uint_32)(dpi * INCHES_PER_METER), + PNG_RESOLUTION_METER); + png_write_info(png_ptr, info_ptr); + + if(type == PNG_TYPE) { + /* top margin */ + memset(row, 0xff, (size_t)((realwidth + 7) / 8)); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + memset(row, 0xff, (size_t)((realwidth + 7) / 8)); + q = row; + q += margin * size / 8; + bit = 7 - (margin * size % 8); + for(x = 0; x < qrcode->width; x++) { + for(xx = 0; xx < size; xx++) { + *q ^= (*p & 1) << bit; + bit--; + if(bit < 0) { + q++; + bit = 7; + } + } + p++; + } + for(yy = 0; yy < size; yy++) { + png_write_row(png_ptr, row); + } + } + /* bottom margin */ + memset(row, 0xff, (size_t)((realwidth + 7) / 8)); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + } else { + /* top margin */ + fillRow(row, realwidth, bg_color); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + fillRow(row, realwidth, bg_color); + for(x = 0; x < qrcode->width; x++) { + for(xx = 0; xx < size; xx++) { + if(*p & 1) { + memcpy(&row[((margin + x) * size + xx) * 4], fg_color, 4); + } + } + p++; + } + for(yy = 0; yy < size; yy++) { + png_write_row(png_ptr, row); + } + } + /* bottom margin */ + fillRow(row, realwidth, bg_color); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + free(row); + free(palette); + + return 0; +#else + fputs("PNG output is disabled at compile time. No output generated.\n", stderr); + return 0; +#endif +} + +static int writeEPS(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + unsigned char *row, *p; + int x, y, yy; + int realwidth; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * size; + /* EPS file header */ + fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n" + "%%%%BoundingBox: 0 0 %d %d\n" + "%%%%Pages: 1 1\n" + "%%%%EndComments\n", realwidth, realwidth); + /* draw point */ + fprintf(fp, "/p { " + "moveto " + "0 1 rlineto " + "1 0 rlineto " + "0 -1 rlineto " + "fill " + "} bind def\n"); + /* set color */ + fprintf(fp, "gsave\n"); + fprintf(fp, "%f %f %f setrgbcolor\n", + (double)bg_color[0] / 255, + (double)bg_color[1] / 255, + (double)bg_color[2] / 255); + fprintf(fp, "%d %d scale\n", realwidth, realwidth); + fprintf(fp, "0 0 p\ngrestore\n"); + fprintf(fp, "%f %f %f setrgbcolor\n", + (double)fg_color[0] / 255, + (double)fg_color[1] / 255, + (double)fg_color[2] / 255); + fprintf(fp, "%d %d scale\n", size, size); + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + row = (p+(y*qrcode->width)); + yy = (margin + qrcode->width - y - 1); + + for(x = 0; x < qrcode->width; x++) { + if(*(row+x)&0x1) { + fprintf(fp, "%d %d p ", margin + x, yy); + } + } + } + + fprintf(fp, "\n%%%%EOF\n"); + fclose(fp); + + return 0; +} + +static void writeSVG_drawModules(FILE *fp, int x, int y, int width, const char* col, double opacity) +{ + if(svg_path) { + fprintf(fp, "M%d,%dh%d", x, y, width); + } else { + if(fg_color[3] != 255) { + fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\ + "fill=\"#%s\" fill-opacity=\"%f\"/>\n", + x, y, width, col, opacity ); + } else { + fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\ + "fill=\"#%s\"/>\n", + x, y, width, col ); + } + } +} + +static int writeSVG(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + unsigned char *row, *p; + int x, y, x0, pen; + int symwidth, realwidth; + double scale; + char fg[7], bg[7]; + double fg_opacity; + double bg_opacity; + + fp = openFile(outfile); + + scale = dpi * INCHES_PER_METER / 100.0; + + symwidth = qrcode->width + margin * 2; + realwidth = symwidth * size; + + snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1], fg_color[2]); + snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1], bg_color[2]); + fg_opacity = (double)fg_color[3] / 255; + bg_opacity = (double)bg_color[3] / 255; + + /* XML declaration */ + if (!inline_svg) + fputs( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", fp ); + + /* DTD + No document type specified because "while a DTD is provided in [the SVG] + specification, the use of DTDs for validating XML documents is known to + be problematic. In particular, DTDs do not handle namespaces gracefully. + It is *not* recommended that a DOCTYPE declaration be included in SVG + documents." + https://www.w3.org/TR/2003/REC-SVG11-20030114/intro.html#Namespace + */ + + /* Vanity remark */ + fprintf(fp, "<!-- Created with qrencode %s (https://fukuchi.org/works/qrencode/index.html) -->\n", QRcode_APIVersionString()); + + /* SVG code start */ + fprintf(fp, + "<svg width=\"%.2fcm\" height=\"%.2fcm\" viewBox=\"0 0 %d %d\""\ + " preserveAspectRatio=\"none\" version=\"1.1\""\ + " xmlns=\"http://www.w3.org/2000/svg\">\n", + (double)realwidth / scale, (double)realwidth / scale, symwidth, symwidth + ); + + /* Make named group */ + fputs("\t<g id=\"QRcode\">\n", fp); + + /* Make solid background */ + if(bg_color[3] != 255) { + fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" fill-opacity=\"%f\"/>\n", symwidth, symwidth, bg, bg_opacity); + } else { + fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\"/>\n", symwidth, symwidth, bg); + } + + if(svg_path) { + if(fg_color[3] != 255) { + fprintf(fp, "\t\t<path style=\"stroke:#%s;stroke-opacity:%f\" transform=\"translate(%d,%d.5)\" d=\"", fg, fg_opacity, margin, margin); + } else { + fprintf(fp, "\t\t<path style=\"stroke:#%s\" transform=\"translate(%d,%d.5)\" d=\"", fg, margin, margin); + } + } else { + /* Create new viewbox for QR data */ + fprintf(fp, "\t\t<g id=\"Pattern\" transform=\"translate(%d,%d)\">\n", margin, margin); + } + + /* Write data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + row = (p+(y*qrcode->width)); + + if( !rle ) { + /* no RLE */ + for(x = 0; x < qrcode->width; x++) { + if(*(row+x)&0x1) { + writeSVG_drawModules(fp, x, y, 1, fg, fg_opacity); + } + } + } else { + /* simple RLE */ + pen = 0; + x0 = 0; + for(x = 0; x < qrcode->width; x++) { + if( !pen ) { + pen = *(row+x)&0x1; + x0 = x; + } else if(!(*(row+x)&0x1)) { + writeSVG_drawModules(fp, x0, y, x-x0, fg, fg_opacity); + pen = 0; + } + } + if( pen ) { + writeSVG_drawModules(fp, x0, y, qrcode->width - x0, fg, fg_opacity); + } + } + } + + if(svg_path) { + fputs("\"/>\n", fp); + } else { + /* Close QR data viewbox */ + fputs("\t\t</g>\n", fp); + } + + /* Close group */ + fputs("\t</g>\n", fp); + + /* Close SVG code */ + fputs("</svg>\n", fp); + fclose(fp); + + return 0; +} + +static int writeXPM(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + int x, xx, y, yy, realwidth, realmargin; + char *row; + char fg[7], bg[7]; + unsigned char *p; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * size; + realmargin = margin * size; + + row = malloc((size_t)realwidth + 1); + if (!row ) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1], fg_color[2]); + snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1], bg_color[2]); + + fputs("/* XPM */\n", fp); + fputs("static const char *const qrcode_xpm[] = {\n", fp); + fputs("/* width height ncolors chars_per_pixel */\n", fp); + fprintf(fp, "\"%d %d 2 1\",\n", realwidth, realwidth); + + fputs("/* colors */\n", fp); + fprintf(fp, "\"F c #%s\",\n", fg); + fprintf(fp, "\"B c #%s\",\n", bg); + + fputs("/* pixels */\n", fp); + memset(row, 'B', (size_t)realwidth); + row[realwidth] = '\0'; + + for (y = 0; y < realmargin; y++) { + fprintf(fp, "\"%s\",\n", row); + } + + p = qrcode->data; + for (y = 0; y < qrcode->width; y++) { + for (yy = 0; yy < size; yy++) { + fputs("\"", fp); + + for (x = 0; x < margin; x++) { + for (xx = 0; xx < size; xx++) { + fputs("B", fp); + } + } + + for (x = 0; x < qrcode->width; x++) { + for (xx = 0; xx < size; xx++) { + if (p[(y * qrcode->width) + x] & 0x1) { + fputs("F", fp); + } else { + fputs("B", fp); + } + } + } + + for (x = 0; x < margin; x++) { + for (xx = 0; xx < size; xx++) { + fputs("B", fp); + } + } + + fputs("\",\n", fp); + } + } + + for (y = 0; y < realmargin; y++) { + fprintf(fp, "\"%s\",\n", row); + } + fputs("};\n", fp); + + free(row); + fclose(fp); + + return 0; +} + +static void writeANSI_margin(FILE* fp, int realwidth, + char* buffer, const char* white, int white_s ) +{ + int y; + + strncpy(buffer, white, (size_t)white_s); + memset(buffer + white_s, ' ', (size_t)realwidth * 2); + strcpy(buffer + white_s + realwidth * 2, "\033[0m\n"); // reset to default colors + for(y = 0; y < margin; y++ ){ + fputs(buffer, fp); + } +} + +static int writeANSI(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + unsigned char *row, *p; + int x, y; + int realwidth; + int last; + + const char *white, *black; + char *buffer; + int white_s, black_s, buffer_s; + + if(image_type == ANSI256_TYPE){ + /* codes for 256 color compatible terminals */ + white = "\033[48;5;231m"; + white_s = 11; + black = "\033[48;5;16m"; + black_s = 10; + } else { + white = "\033[47m"; + white_s = 5; + black = "\033[40m"; + black_s = 5; + } + + size = 1; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * size; + buffer_s = (realwidth * white_s) * 2; + buffer = (char *)malloc((size_t)buffer_s); + if(buffer == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + /* top margin */ + writeANSI_margin(fp, realwidth, buffer, white, white_s); + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + row = (p+(y*qrcode->width)); + + memset(buffer, 0, (size_t)buffer_s); + strncpy(buffer, white, (size_t)white_s); + for(x = 0; x < margin; x++ ){ + strncat(buffer, " ", 2); + } + last = 0; + + for(x = 0; x < qrcode->width; x++) { + if(*(row+x)&0x1) { + if( last != 1 ){ + strncat(buffer, black, (size_t)black_s); + last = 1; + } + } else if( last != 0 ){ + strncat(buffer, white, (size_t)white_s); + last = 0; + } + strncat(buffer, " ", 2); + } + + if( last != 0 ){ + strncat(buffer, white, (size_t)white_s); + } + for(x = 0; x < margin; x++ ){ + strncat(buffer, " ", 2); + } + strncat(buffer, "\033[0m\n", 5); + fputs(buffer, fp); + } + + /* bottom margin */ + writeANSI_margin(fp, realwidth, buffer, white, white_s); + + fclose(fp); + free(buffer); + + return 0; +} + +static void writeUTF8_margin(FILE* fp, int realwidth, const char* white, + const char *reset, const char* full) +{ + int x, y; + + for (y = 0; y < margin/2; y++) { + fputs(white, fp); + for (x = 0; x < realwidth; x++) + fputs(full, fp); + fputs(reset, fp); + fputc('\n', fp); + } +} + +static int writeUTF8(const QRcode *qrcode, const char *outfile, int use_ansi, int invert) +{ + FILE *fp; + int x, y; + int realwidth; + const char *white, *reset; + const char *empty, *lowhalf, *uphalf, *full; + + empty = " "; + lowhalf = "\342\226\204"; + uphalf = "\342\226\200"; + full = "\342\226\210"; + + if (invert) { + const char *tmp; + + tmp = empty; + empty = full; + full = tmp; + + tmp = lowhalf; + lowhalf = uphalf; + uphalf = tmp; + } + + if (use_ansi){ + if (use_ansi == 2) { + white = "\033[38;5;231m\033[48;5;16m"; + } else { + white = "\033[40;37;1m"; + } + reset = "\033[0m"; + } else { + white = ""; + reset = ""; + } + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2); + + /* top margin */ + writeUTF8_margin(fp, realwidth, white, reset, full); + + /* data */ + for(y = 0; y < qrcode->width; y += 2) { + unsigned char *row1, *row2; + row1 = qrcode->data + y*qrcode->width; + row2 = row1 + qrcode->width; + + fputs(white, fp); + + for (x = 0; x < margin; x++) { + fputs(full, fp); + } + + for (x = 0; x < qrcode->width; x++) { + if(row1[x] & 1) { + if(y < qrcode->width - 1 && row2[x] & 1) { + fputs(empty, fp); + } else { + fputs(lowhalf, fp); + } + } else if(y < qrcode->width - 1 && row2[x] & 1) { + fputs(uphalf, fp); + } else { + fputs(full, fp); + } + } + + for (x = 0; x < margin; x++) + fputs(full, fp); + + fputs(reset, fp); + fputc('\n', fp); + } + + /* bottom margin */ + writeUTF8_margin(fp, realwidth, white, reset, full); + + fclose(fp); + + return 0; +} + +static void writeASCII_margin(FILE* fp, int realwidth, char* buffer, int invert) +{ + int y, h; + + h = margin; + + memset(buffer, (invert?'#':' '), (size_t)realwidth); + buffer[realwidth] = '\n'; + buffer[realwidth + 1] = '\0'; + for(y = 0; y < h; y++ ){ + fputs(buffer, fp); + } +} + +static int writeASCII(const QRcode *qrcode, const char *outfile, int invert) +{ + FILE *fp; + unsigned char *row; + int x, y; + int realwidth; + char *buffer, *p; + int buffer_s; + char black = '#'; + char white = ' '; + + if(invert) { + black = ' '; + white = '#'; + } + + size = 1; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * 2; + buffer_s = realwidth + 2; + buffer = (char *)malloc((size_t)buffer_s); + if(buffer == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + /* top margin */ + writeASCII_margin(fp, realwidth, buffer, invert); + + /* data */ + for(y = 0; y < qrcode->width; y++) { + row = qrcode->data+(y*qrcode->width); + p = buffer; + + memset(p, white, (size_t)margin * 2); + p += margin * 2; + + for(x = 0; x < qrcode->width; x++) { + if(row[x]&0x1) { + *p++ = black; + *p++ = black; + } else { + *p++ = white; + *p++ = white; + } + } + + memset(p, white, (size_t)margin * 2); + p += margin * 2; + *p++ = '\n'; + *p++ = '\0'; + fputs( buffer, fp ); + } + + /* bottom margin */ + writeASCII_margin(fp, realwidth, buffer, invert); + + fclose(fp); + free(buffer); + + return 0; +} + +static QRcode *encode(const unsigned char *intext, int length) +{ + QRcode *code; + + if(micro) { + if(eightbit) { + code = QRcode_encodeDataMQR(length, intext, version, level); + } else { + code = QRcode_encodeStringMQR((const char *)intext, version, level, hint, casesensitive); + } + } else if(eightbit) { + code = QRcode_encodeData(length, intext, version, level); + } else { + code = QRcode_encodeString((const char *)intext, version, level, hint, casesensitive); + } + + return code; +} + +static void qrencode(const unsigned char *intext, int length, const char *outfile) +{ + QRcode *qrcode; + + qrcode = encode(intext, length); + if(qrcode == NULL) { + if(errno == ERANGE) { + fprintf(stderr, "Failed to encode the input data: Input data too large\n"); + } else { + perror("Failed to encode the input data"); + } + exit(EXIT_FAILURE); + } + if(strict_versioning && version > 0 && qrcode->version != version) { + fprintf(stderr, "Failed to encode the input data: Input data too large\n"); + exit(EXIT_FAILURE); + } + + if(verbose) { + fprintf(stderr, "File: %s, Version: %d\n", (outfile!=NULL)?outfile:"(stdout)", qrcode->version); + } + + switch(image_type) { + case PNG_TYPE: + case PNG32_TYPE: + writePNG(qrcode, outfile, image_type); + break; + case EPS_TYPE: + writeEPS(qrcode, outfile); + break; + case SVG_TYPE: + writeSVG(qrcode, outfile); + break; + case XPM_TYPE: + writeXPM(qrcode, outfile); + break; + case ANSI_TYPE: + case ANSI256_TYPE: + writeANSI(qrcode, outfile); + break; + case ASCII_TYPE: + writeASCII(qrcode, outfile, 1); + break; + case ASCIIi_TYPE: + writeASCII(qrcode, outfile, 0); + break; + case UTF8_TYPE: + writeUTF8(qrcode, outfile, 0, 0); + break; + case ANSIUTF8_TYPE: + writeUTF8(qrcode, outfile, 1, 0); + break; + case ANSI256UTF8_TYPE: + writeUTF8(qrcode, outfile, 2, 0); + break; + case UTF8i_TYPE: + writeUTF8(qrcode, outfile, 0, 1); + break; + case ANSIUTF8i_TYPE: + writeUTF8(qrcode, outfile, 1, 1); + break; + } + + QRcode_free(qrcode); +} + +static QRcode_List *encodeStructured(const unsigned char *intext, int length) +{ + QRcode_List *list; + + if(eightbit) { + list = QRcode_encodeDataStructured(length, intext, version, level); + } else { + list = QRcode_encodeStringStructured((const char *)intext, version, level, hint, casesensitive); + } + + return list; +} + +static void qrencodeStructured(const unsigned char *intext, int length, const char *outfile) +{ + QRcode_List *qrlist, *p; + char filename[FILENAME_MAX]; + char *base, *q, *suffix = NULL; + const char *type_suffix; + int i = 1; + size_t suffix_size; + + switch(image_type) { + case PNG_TYPE: + case PNG32_TYPE: + type_suffix = ".png"; + break; + case EPS_TYPE: + type_suffix = ".eps"; + break; + case SVG_TYPE: + type_suffix = ".svg"; + break; + case XPM_TYPE: + type_suffix = ".xpm"; + break; + case ANSI_TYPE: + case ANSI256_TYPE: + case ANSI256UTF8_TYPE: + case ASCII_TYPE: + case ASCIIi_TYPE: + case UTF8_TYPE: + case ANSIUTF8_TYPE: + case UTF8i_TYPE: + case ANSIUTF8i_TYPE: + type_suffix = ".txt"; + break; + } + + if(outfile == NULL) { + fprintf(stderr, "An output filename must be specified to store the structured images.\n"); + exit(EXIT_FAILURE); + } + base = strdup(outfile); + if(base == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + suffix_size = strlen(type_suffix); + if(strlen(base) > suffix_size) { + q = base + strlen(base) - suffix_size; + if(strcasecmp(type_suffix, q) == 0) { + suffix = strdup(q); + *q = '\0'; + } + } + + qrlist = encodeStructured(intext, length); + if(qrlist == NULL) { + if(errno == ERANGE) { + fprintf(stderr, "Failed to encode the input data: Input data too large\n"); + } else { + perror("Failed to encode the input data"); + } + exit(EXIT_FAILURE); + } + + for(p = qrlist; p != NULL; p = p->next) { + if(p->code == NULL) { + fprintf(stderr, "Failed to encode the input data.\n"); + exit(EXIT_FAILURE); + } + if(suffix) { + snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix); + } else { + snprintf(filename, FILENAME_MAX, "%s-%02d", base, i); + } + + if(verbose) { + fprintf(stderr, "File: %s, Version: %d\n", filename, p->code->version); + } + + switch(image_type) { + case PNG_TYPE: + case PNG32_TYPE: + writePNG(p->code, filename, image_type); + break; + case EPS_TYPE: + writeEPS(p->code, filename); + break; + case SVG_TYPE: + writeSVG(p->code, filename); + break; + case XPM_TYPE: + writeXPM(p->code, filename); + break; + case ANSI_TYPE: + case ANSI256_TYPE: + writeANSI(p->code, filename); + break; + case ASCII_TYPE: + writeASCII(p->code, filename, 1); + break; + case ASCIIi_TYPE: + writeASCII(p->code, filename, 0); + break; + case UTF8_TYPE: + writeUTF8(p->code, filename, 0, 0); + break; + case ANSIUTF8_TYPE: + writeUTF8(p->code, filename, 1, 0); + break; + case ANSI256UTF8_TYPE: + writeUTF8(p->code, filename, 2, 0); + break; + case UTF8i_TYPE: + writeUTF8(p->code, filename, 0, 1); + break; + case ANSIUTF8i_TYPE: + writeUTF8(p->code, filename, 1, 1); + break; + } + i++; + } + + free(base); + if(suffix) { + free(suffix); + } + + QRcode_List_free(qrlist); +} + +int main(int argc, char **argv) +{ + int opt, lindex = -1; + char *outfile = NULL, *infile = NULL; + unsigned char *intext = NULL; + int length = 0; + FILE *fp; + + while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) { + switch(opt) { + case 'h': + if(lindex == 0) { + usage(1, 1, EXIT_SUCCESS); + } else { + usage(1, 0, EXIT_SUCCESS); + } + exit(EXIT_SUCCESS); + case 'o': + outfile = optarg; + break; + case 'r': + infile = optarg; + break; + case 's': + size = atoi(optarg); + if(size <= 0) { + fprintf(stderr, "Invalid size: %d\n", size); + exit(EXIT_FAILURE); + } + break; + case 'v': + version = atoi(optarg); + if(version < 0) { + fprintf(stderr, "Invalid version: %d\n", version); + exit(EXIT_FAILURE); + } + break; + case 'l': + switch(*optarg) { + case 'l': + case 'L': + level = QR_ECLEVEL_L; + break; + case 'm': + case 'M': + level = QR_ECLEVEL_M; + break; + case 'q': + case 'Q': + level = QR_ECLEVEL_Q; + break; + case 'h': + case 'H': + level = QR_ECLEVEL_H; + break; + default: + fprintf(stderr, "Invalid level: %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 'm': + margin = atoi(optarg); + if(margin < 0) { + fprintf(stderr, "Invalid margin: %d\n", margin); + exit(EXIT_FAILURE); + } + break; + case 'd': + dpi = atoi(optarg); + if( dpi < 0 ) { + fprintf(stderr, "Invalid DPI: %d\n", dpi); + exit(EXIT_FAILURE); + } + break; + case 't': + if(strcasecmp(optarg, "png32") == 0) { + image_type = PNG32_TYPE; + } else if(strcasecmp(optarg, "png") == 0) { + image_type = PNG_TYPE; + } else if(strcasecmp(optarg, "eps") == 0) { + image_type = EPS_TYPE; + } else if(strcasecmp(optarg, "svg") == 0) { + image_type = SVG_TYPE; + } else if(strcasecmp(optarg, "xpm") == 0) { + image_type = XPM_TYPE; + } else if(strcasecmp(optarg, "ansi") == 0) { + image_type = ANSI_TYPE; + } else if(strcasecmp(optarg, "ansi256") == 0) { + image_type = ANSI256_TYPE; + } else if(strcasecmp(optarg, "asciii") == 0) { + image_type = ASCIIi_TYPE; + } else if(strcasecmp(optarg, "ascii") == 0) { + image_type = ASCII_TYPE; + } else if(strcasecmp(optarg, "utf8") == 0) { + image_type = UTF8_TYPE; + } else if(strcasecmp(optarg, "ansiutf8") == 0) { + image_type = ANSIUTF8_TYPE; + } else if(strcasecmp(optarg, "ansi256utf8") == 0) { + image_type = ANSI256UTF8_TYPE; + } else if(strcasecmp(optarg, "utf8i") == 0) { + image_type = UTF8i_TYPE; + } else if(strcasecmp(optarg, "ansiutf8i") == 0) { + image_type = ANSIUTF8i_TYPE; + } else { + fprintf(stderr, "Invalid image type: %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 'S': + structured = 1; + break; + case 'k': + hint = QR_MODE_KANJI; + break; + case 'c': + casesensitive = 1; + break; + case 'i': + casesensitive = 0; + break; + case '8': + eightbit = 1; + break; + case 'M': + micro = 1; + break; + case 'f': + if(color_set(fg_color, optarg)) { + fprintf(stderr, "Invalid foreground color value.\n"); + exit(EXIT_FAILURE); + } + break; + case 'b': + if(color_set(bg_color, optarg)) { + fprintf(stderr, "Invalid background color value.\n"); + exit(EXIT_FAILURE); + } + break; + case 'V': + usage(0, 0, EXIT_SUCCESS); + exit(EXIT_SUCCESS); + case 0: + break; + default: + fprintf(stderr, "Try \"qrencode --help\" for more information.\n"); + exit(EXIT_FAILURE); + } + } + + if(argc == 1) { + usage(1, 0, EXIT_FAILURE); + exit(EXIT_FAILURE); + } + + if(outfile == NULL && image_type == PNG_TYPE) { + fprintf(stderr, "No output filename is given.\n"); + exit(EXIT_FAILURE); + } + + if(optind < argc) { + intext = (unsigned char *)argv[optind]; + length = (int)strlen((char *)intext); + } + if(intext == NULL) { + fp = infile == NULL ? stdin : fopen(infile, "r"); + if(fp == 0) { + fprintf(stderr, "Cannot read input file %s.\n", infile); + exit(EXIT_FAILURE); + } + intext = readFile(fp, &length); + + } + + if(micro && version > MQRSPEC_VERSION_MAX) { + fprintf(stderr, "Version number should be less or equal to %d.\n", MQRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } else if(!micro && version > QRSPEC_VERSION_MAX) { + fprintf(stderr, "Version number should be less or equal to %d.\n", QRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } + + if(margin < 0) { + if(micro) { + margin = 2; + } else { + margin = 4; + } + } + + if(micro) { + if(structured) { + fprintf(stderr, "Micro QR Code does not support structured symbols.\n"); + exit(EXIT_FAILURE); + } + } + + if(structured) { + if(version == 0) { + fprintf(stderr, "Version number must be specified to encode structured symbols.\n"); + exit(EXIT_FAILURE); + } + qrencodeStructured(intext, length, outfile); + } else { + qrencode(intext, length, outfile); + } + + return 0; +} diff --git a/genqrcode/qrencode.1.in b/genqrcode/qrencode.1.in new file mode 100644 index 0000000000..c61e0b1ad9 --- /dev/null +++ b/genqrcode/qrencode.1.in @@ -0,0 +1,140 @@ +.TH QRENCODE 1 "Aug. 28, 2020" "qrencode @VERSION@" +.SH NAME +qrencode \- Encode input data in a QR Code and save as a PNG or EPS image. +.SH SYNOPSIS +.B "qrencode" +[-o FILENAME] +[OPTION]... +[STRING] + +.SH DESCRIPTION +Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D +symbology that can be scanned by handy terminals such as a mobile phone with +CCD. The capacity of QR Code is up to 7000 digits or 4000 characters, and has +high robustness. + +Qrencode is a utility software using libqrencode to encode string data in +a QR Code and save as a PNG or EPS image. + +.SH OPTIONS +.TP +.B \-h, \-\-help +display help message. +.TP +.B \-o FILENAME, \-\-output=FILENAME +write image to FILENAME. If '\-' is specified, the result will be output to standard output. If \-S is given, structured symbols are written to FILENAME-01.png, FILENAME-02.png, ... (suffix is removed from FILENAME, if specified) +.TP +.B \-r FILENAME, \-\-read\-from=FILENAME +read input data from FILENAME. +.TP +.B \-s NUMBER, \-\-size=NUMBER +specify the size of dot (pixel). (default=3) +.TP +.B \-l {LMQH}, \-\-level={LMQH} +specify error correction level from L (lowest) to H (highest). (default=L) +.TP +.B \-v NUMBER, \-\-symversion=NUMBER +specify the minimum version of the symbol. See SYMBOL VERSIONS for more information. (default=auto) +.TP +.B \-m NUMBER, \-\-margin=NUMBER +specify the width of margin. (default=4) +.TP +.B \-d NUMBER, \-\-dpi=NUMBER +specify the DPI of the generated PNG. (default=72) +.TP +.PD 0 +.B \-t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8} +.TP +.PD +.B \-\-type={PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8} +specify the type of the generated image. (default=PNG) +.br +If ASCII*, UTF8*, or ANSI* is specified, the image will be displayed in the terminal by using +text characters instead of generating an image file. If the name of the type is followed by 'i', +the light/dark character will be reversed. +.TP +.B \-S, \-\-structured +make structured symbols. Version number must be specified with '-v'. +.TP +.B \-k, \-\-kanji +assume that the input text contains kanji (shift-jis). +.TP +.B \-c, \-\-casesensitive +encode lower-case alphabet characters in 8-bit mode. (default) +.TP +.B \-i, \-\-ignorecase +ignore case distinctions and use only upper-case characters. +.TP +.B \-8, \-\-8bit +encode entire data in 8-bit mode. \-k, \-c and \-i will be ignored. +.TP +.B \-M, \-\-micro +encode in a Micro QR Code. See MICRO QR CODE for more information. +.TP +.B \-\-rle +enable run-length encoding for SVG. +.TP +.B \-\-svg-path +use single path to draw modules for SVG. +.TP +.B \-\-inline +only useful for SVG output, generates an SVG without the XML tag. +.TP +.PD 0 +.B \-\-foreground=RRGGBB[AA] +.TP +.PD +.B \-\-background=RRGGBB[AA] +specify foreground/background color in hexadecimal notation. +6-digit (RGB) or 8-digit (RGBA) form are supported. +Color output support available only in PNG, EPS and SVG. +.TP +.B \-\-strict\-version +disable automatic version number adjustment. If the input data is +too large for the specified version, the program exits with the +code of 1. +.TP +.B \-V, \-\-version +display the version number and copyrights of the qrencode. +.TP +.B \-\-verbose +display verbose information to stderr. +.TP +.B [STRING] +input data. If it is not specified, data will be taken from standard input. + +.SH SYMBOL VERSIONS +The symbol versions of QR Code range from Version 1 to Version 40. +Each version has a different module configuration or number of modules, +ranging from Version 1 (21 x 21 modules) up to Version 40 (177 x 177 modules). +Each higher version number comprises 4 additional modules per side by default. +See http://www.qrcode.com/en/about/version.html for a detailed version list. + +.SH MICRO QR CODE +With Micro QR Code, You can embed data in a smaller area than with QR Code, +but the data capacity is strongly limited. The symbol versions range from +Version 1 to 4. + +.SH EXAMPLES +.TP +.B qrencode \-l L \-v 1 \-o output.png 'Hello, world!' +encode into a symbol version 1, level L. +.TP +.B qrencode \-iSv 1 \-\-output=output.png +read standard input and encode it into a structured-appended symbols in +case-insensitive mode. +.TP +.B qrencode \-S \-v 40 \-l L \-r bigfile.txt \-o output.png +read input data from bigfile.txt and encode into a symbol version 40, level L. + +.SH AUTHOR +Written by Kentaro Fukuchi. + +.SH RESOURCES +.TP +Main Web Site: https://fukuchi.org/works/qrencode/ +.TP +Source code repository: https://github.com/fukuchi/libqrencode/ + +.SH COPYRIGHT +Copyright (C) 2006-2018, 2020 Kentaro Fukuchi. diff --git a/genqrcode/qrencode.c b/genqrcode/qrencode.c new file mode 100644 index 0000000000..948d1626ce --- /dev/null +++ b/genqrcode/qrencode.c @@ -0,0 +1,921 @@ +/* + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2018, 2020 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "qrencode.h" +#include "qrspec.h" +#include "mqrspec.h" +#include "bitstream.h" +#include "qrinput.h" +#include "rsecc.h" +#include "split.h" +#include "mask.h" +#include "mmask.h" + +/****************************************************************************** + * Raw code + *****************************************************************************/ + +typedef struct { + int dataLength; + int eccLength; + unsigned char *data; + unsigned char *ecc; +} RSblock; + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + int b1; + int blocks; + RSblock *rsblock; + int count; +} QRRawCode; + +static void RSblock_initBlock(RSblock *block, int dl, unsigned char *data, int el, unsigned char *ecc) +{ + block->dataLength = dl; + block->data = data; + block->eccLength = el; + block->ecc = ecc; + + RSECC_encode((size_t)dl, (size_t)el, data, ecc); +} + +static int RSblock_init(RSblock *blocks, int spec[5], unsigned char *data, unsigned char *ecc) +{ + int i; + RSblock *block; + unsigned char *dp, *ep; + int el, dl; + + dl = QRspec_rsDataCodes1(spec); + el = QRspec_rsEccCodes1(spec); + + block = blocks; + dp = data; + ep = ecc; + for(i = 0; i < QRspec_rsBlockNum1(spec); i++) { + RSblock_initBlock(block, dl, dp, el, ep); + dp += dl; + ep += el; + block++; + } + + if(QRspec_rsBlockNum2(spec) == 0) return 0; + + dl = QRspec_rsDataCodes2(spec); + el = QRspec_rsEccCodes2(spec); + for(i = 0; i < QRspec_rsBlockNum2(spec); i++) { + RSblock_initBlock(block, dl, dp, el, ep); + dp += dl; + ep += el; + block++; + } + + return 0; +} + +STATIC_IN_RELEASE void QRraw_free(QRRawCode *raw); +STATIC_IN_RELEASE QRRawCode *QRraw_new(QRinput *input) +{ + QRRawCode *raw; + int spec[5], ret; + + raw = (QRRawCode *)malloc(sizeof(QRRawCode)); + if(raw == NULL) return NULL; + + raw->datacode = QRinput_getByteStream(input); + if(raw->datacode == NULL) { + free(raw); + return NULL; + } + + QRspec_getEccSpec(input->version, input->level, spec); + + raw->version = input->version; + raw->b1 = QRspec_rsBlockNum1(spec); + raw->dataLength = QRspec_rsDataLength(spec); + raw->eccLength = QRspec_rsEccLength(spec); + raw->ecccode = (unsigned char *)malloc((size_t)raw->eccLength); + if(raw->ecccode == NULL) { + free(raw->datacode); + free(raw); + return NULL; + } + + raw->blocks = QRspec_rsBlockNum(spec); + raw->rsblock = (RSblock *)calloc((size_t)(raw->blocks), sizeof(RSblock)); + if(raw->rsblock == NULL) { + QRraw_free(raw); + return NULL; + } + ret = RSblock_init(raw->rsblock, spec, raw->datacode, raw->ecccode); + if(ret < 0) { + QRraw_free(raw); + return NULL; + } + + raw->count = 0; + + return raw; +} + +/** + * Return a code (byte). + * This function can be called iteratively. + * @param raw raw code. + * @return code + */ +STATIC_IN_RELEASE unsigned char QRraw_getCode(QRRawCode *raw) +{ + int col, row; + unsigned char ret; + + if(raw->count < raw->dataLength) { + row = raw->count % raw->blocks; + col = raw->count / raw->blocks; + if(col >= raw->rsblock[0].dataLength) { + row += raw->b1; + } + ret = raw->rsblock[row].data[col]; + } else if(raw->count < raw->dataLength + raw->eccLength) { + row = (raw->count - raw->dataLength) % raw->blocks; + col = (raw->count - raw->dataLength) / raw->blocks; + ret = raw->rsblock[row].ecc[col]; + } else { + return 0; + } + raw->count++; + return ret; +} + +STATIC_IN_RELEASE void QRraw_free(QRRawCode *raw) +{ + if(raw != NULL) { + free(raw->datacode); + free(raw->ecccode); + free(raw->rsblock); + free(raw); + } +} + +/****************************************************************************** + * Raw code for Micro QR Code + *****************************************************************************/ + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + RSblock *rsblock; + int oddbits; + int count; +} MQRRawCode; + +STATIC_IN_RELEASE void MQRraw_free(MQRRawCode *raw); +STATIC_IN_RELEASE MQRRawCode *MQRraw_new(QRinput *input) +{ + MQRRawCode *raw; + + raw = (MQRRawCode *)malloc(sizeof(MQRRawCode)); + if(raw == NULL) return NULL; + + raw->version = input->version; + raw->dataLength = MQRspec_getDataLength(input->version, input->level); + raw->eccLength = MQRspec_getECCLength(input->version, input->level); + raw->oddbits = raw->dataLength * 8 - MQRspec_getDataLengthBit(input->version, input->level); + raw->datacode = QRinput_getByteStream(input); + if(raw->datacode == NULL) { + free(raw); + return NULL; + } + raw->ecccode = (unsigned char *)malloc((size_t)raw->eccLength); + if(raw->ecccode == NULL) { + free(raw->datacode); + free(raw); + return NULL; + } + + raw->rsblock = (RSblock *)calloc(1, sizeof(RSblock)); + if(raw->rsblock == NULL) { + MQRraw_free(raw); + return NULL; + } + + RSblock_initBlock(raw->rsblock, raw->dataLength, raw->datacode, raw->eccLength, raw->ecccode); + + raw->count = 0; + + return raw; +} + +/** + * Return a code (byte). + * This function can be called iteratively. + * @param raw raw code. + * @return code + */ +STATIC_IN_RELEASE unsigned char MQRraw_getCode(MQRRawCode *raw) +{ + unsigned char ret; + + if(raw->count < raw->dataLength) { + ret = raw->datacode[raw->count]; + } else if(raw->count < raw->dataLength + raw->eccLength) { + ret = raw->ecccode[raw->count - raw->dataLength]; + } else { + return 0; + } + raw->count++; + return ret; +} + +STATIC_IN_RELEASE void MQRraw_free(MQRRawCode *raw) +{ + if(raw != NULL) { + free(raw->datacode); + free(raw->ecccode); + free(raw->rsblock); + free(raw); + } +} + + +/****************************************************************************** + * Frame filling + *****************************************************************************/ + +typedef struct { + int width; + unsigned char *frame; + int x, y; + int dir; + int bit; + int mqr; +} FrameFiller; + +static void FrameFiller_set(FrameFiller *filler, int width, unsigned char *frame, int mqr) +{ + filler->width = width; + filler->frame = frame; + filler->x = width - 1; + filler->y = width - 1; + filler->dir = -1; + filler->bit = -1; + filler->mqr = mqr; +} + +static unsigned char *FrameFiller_next(FrameFiller *filler) +{ + int x, y, w; + + x = filler->x; + y = filler->y; + w = filler->width; + for(;;) { + if(filler->bit == -1) { + filler->bit = 0; + break; + } + + if(filler->bit == 0) { + x--; + filler->bit++; + } else { + x++; + y += filler->dir; + filler->bit--; + } + + if(filler->dir < 0) { + if(y < 0) { + y = 0; + x -= 2; + filler->dir = 1; + if(!filler->mqr && x == 6) { + x--; + y = 9; + } + } + } else if(y == w) { + y = w - 1; + x -= 2; + filler->dir = -1; + if(!filler->mqr && x == 6) { + x--; + y -= 8; + } + } + if(x < 0 || y < 0) return NULL; + + if(!(filler->frame[y * w + x] & 0x80)) { + break; + } + } + filler->x = x; + filler->y = y; + return &filler->frame[filler->y * w + filler->x]; +} + +#ifdef WITH_TESTS +unsigned char *FrameFiller_test(int version) +{ + int width; + unsigned char *frame, *p; + int i, length; + FrameFiller filler; + + width = QRspec_getWidth(version); + frame = QRspec_newFrame(version); + if(frame == NULL) return NULL; + FrameFiller_set(&filler, width, frame, 0); + length = QRspec_getDataLength(version, QR_ECLEVEL_L) * 8 + + QRspec_getECCLength(version, QR_ECLEVEL_L) * 8 + + QRspec_getRemainder(version); + for(i = 0; i < length; i++) { + p = FrameFiller_next(&filler); + if(p == NULL) { + free(frame); + return NULL; + } + *p = (unsigned char)(i & 0x7f) | 0x80; + } + return frame; +} + +unsigned char *FrameFiller_testMQR(int version) +{ + int width; + unsigned char *frame, *p; + int i, length; + FrameFiller filler; + + width = MQRspec_getWidth(version); + frame = MQRspec_newFrame(version); + if(frame == NULL) return NULL; + FrameFiller_set(&filler, width, frame, 1); + length = MQRspec_getDataLengthBit(version, QR_ECLEVEL_L) + + MQRspec_getECCLength(version, QR_ECLEVEL_L) * 8; + for(i = 0; i < length; i++) { + p = FrameFiller_next(&filler); + if(p == NULL) { + fprintf(stderr, "Frame filler run over the frame!\n"); + return frame; + } + *p = (unsigned char)(i & 0x7f) | 0x80; + } + return frame; +} +#endif + + +/****************************************************************************** + * QR-code encoding + *****************************************************************************/ + +STATIC_IN_RELEASE QRcode *QRcode_new(int version, int width, unsigned char *data) +{ + QRcode *qrcode; + + qrcode = (QRcode *)malloc(sizeof(QRcode)); + if(qrcode == NULL) return NULL; + + qrcode->version = version; + qrcode->width = width; + qrcode->data = data; + + return qrcode; +} + +void QRcode_free(QRcode *qrcode) +{ + if(qrcode != NULL) { + free(qrcode->data); + free(qrcode); + } +} + +STATIC_IN_RELEASE QRcode *QRcode_encodeMask(QRinput *input, int mask) +{ + int width, version; + QRRawCode *raw; + unsigned char *frame, *masked, *p, code, bit; + int i, j; + QRcode *qrcode = NULL; + FrameFiller filler; + + if(input->mqr) { + errno = EINVAL; + return NULL; + } + if(input->version < 0 || input->version > QRSPEC_VERSION_MAX) { + errno = EINVAL; + return NULL; + } + if(!(input->level >= QR_ECLEVEL_L && input->level <= QR_ECLEVEL_H)) { + errno = EINVAL; + return NULL; + } + + raw = QRraw_new(input); + if(raw == NULL) return NULL; + + version = raw->version; + width = QRspec_getWidth(version); + frame = QRspec_newFrame(version); + if(frame == NULL) { + QRraw_free(raw); + return NULL; + } + FrameFiller_set(&filler, width, frame, 0); + + /* interleaved data and ecc codes */ + for(i = 0; i < raw->dataLength; i++) { + code = QRraw_getCode(raw); + bit = 0x80; + for(j = 0; j < 8; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = ((bit & code) != 0); + bit = bit >> 1; + } + } + for(i = 0; i < raw->eccLength; i++) { + code = QRraw_getCode(raw); + bit = 0x80; + for(j = 0; j < 8; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } + QRraw_free(raw); + raw = NULL; + /* remainder bits */ + j = QRspec_getRemainder(version); + for(i = 0; i < j; i++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = 0x02; + } + + /* masking */ + if(mask == -2) { // just for debug purpose + masked = (unsigned char *)malloc((size_t)(width * width)); + memcpy(masked, frame, (size_t)(width * width)); + } else if(mask < 0) { + masked = Mask_mask(width, frame, input->level); + } else { + masked = Mask_makeMask(width, frame, mask, input->level); + } + if(masked == NULL) { + goto EXIT; + } + qrcode = QRcode_new(version, width, masked); + if(qrcode == NULL) { + free(masked); + } + +EXIT: + QRraw_free(raw); + free(frame); + return qrcode; +} + +STATIC_IN_RELEASE QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask) +{ + int width, version; + MQRRawCode *raw; + unsigned char *frame, *masked, *p, code, bit; + int i, j, length; + QRcode *qrcode = NULL; + FrameFiller filler; + + if(!input->mqr) { + errno = EINVAL; + return NULL; + } + if(input->version <= 0 || input->version > MQRSPEC_VERSION_MAX) { + errno = EINVAL; + return NULL; + } + if(!(input->level >= QR_ECLEVEL_L && input->level <= QR_ECLEVEL_Q)) { + errno = EINVAL; + return NULL; + } + + raw = MQRraw_new(input); + if(raw == NULL) return NULL; + + version = raw->version; + width = MQRspec_getWidth(version); + frame = MQRspec_newFrame(version); + if(frame == NULL) { + MQRraw_free(raw); + return NULL; + } + FrameFiller_set(&filler, width, frame, 1); + + /* interleaved data and ecc codes */ + for(i = 0; i < raw->dataLength; i++) { + code = MQRraw_getCode(raw); + bit = 0x80; + if(raw->oddbits && i == raw->dataLength - 1) { + length = raw->oddbits; + } else { + length = 8; + } + for(j = 0; j < length; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = ((bit & code) != 0); + bit = bit >> 1; + } + } + for(i = 0; i < raw->eccLength; i++) { + code = MQRraw_getCode(raw); + bit = 0x80; + length = 8; + for(j = 0; j < length; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } + MQRraw_free(raw); + raw = NULL; + + /* masking */ + if(mask == -2) { // just for debug purpose + masked = (unsigned char *)malloc((size_t)(width * width)); + memcpy(masked, frame, (size_t)(width * width)); + } else if(mask < 0) { + masked = MMask_mask(version, frame, input->level); + } else { + masked = MMask_makeMask(version, frame, mask, input->level); + } + if(masked == NULL) { + goto EXIT; + } + + qrcode = QRcode_new(version, width, masked); + if(qrcode == NULL) { + free(masked); + } + +EXIT: + MQRraw_free(raw); + free(frame); + return qrcode; +} + +QRcode *QRcode_encodeInput(QRinput *input) +{ + if(input->mqr) { + return QRcode_encodeMaskMQR(input, -1); + } else { + return QRcode_encodeMask(input, -1); + } +} + +static QRcode *QRcode_encodeStringReal(const char *string, int version, QRecLevel level, int mqr, QRencodeMode hint, int casesensitive) +{ + QRinput *input; + QRcode *code; + int ret; + + if(string == NULL) { + errno = EINVAL; + return NULL; + } + if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) { + errno = EINVAL; + return NULL; + } + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) return NULL; + + ret = Split_splitStringToQRinput(string, input, hint, casesensitive); + if(ret < 0) { + QRinput_free(input); + return NULL; + } + code = QRcode_encodeInput(input); + QRinput_free(input); + + return code; +} + +QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + return QRcode_encodeStringReal(string, version, level, 0, hint, casesensitive); +} + +QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + int i; + + if(version == 0) { + version = 1; + } + for(i = version; i <= MQRSPEC_VERSION_MAX ; i++) { + QRcode *code = QRcode_encodeStringReal(string, i, level, 1, hint, casesensitive); + if(code != NULL) return code; + } + + return NULL; +} + +static QRcode *QRcode_encodeDataReal(const unsigned char *data, int length, int version, QRecLevel level, int mqr) +{ + QRinput *input; + QRcode *code; + int ret; + + if(data == NULL || length == 0) { + errno = EINVAL; + return NULL; + } + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) return NULL; + + ret = QRinput_append(input, QR_MODE_8, length, data); + if(ret < 0) { + QRinput_free(input); + return NULL; + } + code = QRcode_encodeInput(input); + QRinput_free(input); + + return code; +} + +QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level) +{ + return QRcode_encodeDataReal(data, size, version, level, 0); +} + +QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataReal((const unsigned char *)string, (int)strlen(string), version, level, 0); +} + +QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level) +{ + int i; + + if(version == 0) { + version = 1; + } + for(i = version; i <= MQRSPEC_VERSION_MAX; i++) { + QRcode *code = QRcode_encodeDataReal(data, size, i, level, 1); + if(code != NULL) return code; + } + + return NULL; +} + +QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level) +{ + int i; + + if(string == NULL) { + errno = EINVAL; + return NULL; + } + if(version == 0) { + version = 1; + } + for(i = version; i <= MQRSPEC_VERSION_MAX; i++) { + QRcode *code = QRcode_encodeDataReal((const unsigned char *)string, (int)strlen(string), i, level, 1); + if(code != NULL) return code; + } + + return NULL; +} + + +/****************************************************************************** + * Structured QR-code encoding + *****************************************************************************/ + +static QRcode_List *QRcode_List_newEntry(void) +{ + QRcode_List *entry; + + entry = (QRcode_List *)malloc(sizeof(QRcode_List)); + if(entry == NULL) return NULL; + + entry->next = NULL; + entry->code = NULL; + + return entry; +} + +static void QRcode_List_freeEntry(QRcode_List *entry) +{ + if(entry != NULL) { + QRcode_free(entry->code); + free(entry); + } +} + +void QRcode_List_free(QRcode_List *qrlist) +{ + QRcode_List *list = qrlist, *next; + + while(list != NULL) { + next = list->next; + QRcode_List_freeEntry(list); + list = next; + } +} + +int QRcode_List_size(QRcode_List *qrlist) +{ + QRcode_List *list = qrlist; + int size = 0; + + while(list != NULL) { + size++; + list = list->next; + } + + return size; +} + +QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s) +{ + QRcode_List *head = NULL; + QRcode_List *tail = NULL; + QRcode_List *entry; + QRinput_InputList *list = s->head; + + while(list != NULL) { + if(head == NULL) { + entry = QRcode_List_newEntry(); + if(entry == NULL) goto ABORT; + head = entry; + tail = head; + } else { + entry = QRcode_List_newEntry(); + if(entry == NULL) goto ABORT; + tail->next = entry; + tail = tail->next; + } + tail->code = QRcode_encodeInput(list->input); + if(tail->code == NULL) { + goto ABORT; + } + list = list->next; + } + + return head; +ABORT: + QRcode_List_free(head); + return NULL; +} + +static QRcode_List *QRcode_encodeInputToStructured(QRinput *input) +{ + QRinput_Struct *s; + QRcode_List *codes; + + s = QRinput_splitQRinputToStruct(input); + if(s == NULL) return NULL; + + codes = QRcode_encodeInputStructured(s); + QRinput_Struct_free(s); + + return codes; +} + +static QRcode_List *QRcode_encodeDataStructuredReal( + int size, const unsigned char *data, + int version, QRecLevel level, + int eightbit, QRencodeMode hint, int casesensitive) +{ + QRinput *input; + QRcode_List *codes; + int ret; + + if(version <= 0) { + errno = EINVAL; + return NULL; + } + if(!eightbit && (hint != QR_MODE_8 && hint != QR_MODE_KANJI)) { + errno = EINVAL; + return NULL; + } + + input = QRinput_new2(version, level); + if(input == NULL) return NULL; + + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, size, data); + } else { + ret = Split_splitStringToQRinput((const char *)data, input, hint, casesensitive); + } + if(ret < 0) { + QRinput_free(input); + return NULL; + } + codes = QRcode_encodeInputToStructured(input); + QRinput_free(input); + + return codes; +} + +QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level) { + return QRcode_encodeDataStructuredReal(size, data, version, level, 1, QR_MODE_NUL, 0); +} + +QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level) { + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataStructured((int)strlen(string), (const unsigned char *)string, version, level); +} + +QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataStructuredReal((int)strlen(string), (const unsigned char *)string, version, level, 0, hint, casesensitive); +} + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version) +{ + if(major_version != NULL) { + *major_version = MAJOR_VERSION; + } + if(minor_version != NULL) { + *minor_version = MINOR_VERSION; + } + if(micro_version != NULL) { + *micro_version = MICRO_VERSION; + } +} + +char *QRcode_APIVersionString(void) +{ + return VERSION; +} + +void QRcode_clearCache(void) +{ + return; +} diff --git a/genqrcode/qrencode.h b/genqrcode/qrencode.h new file mode 100644 index 0000000000..3460866321 --- /dev/null +++ b/genqrcode/qrencode.h @@ -0,0 +1,593 @@ +/** + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2018, 2020 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** \mainpage + * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D + * symbology. + * + * \section encoding Encoding + * + * There are two methods to encode data: <b>encoding a string/data</b> or + * <b>encoding a structured data</b>. + * + * \subsection encoding-string Encoding a string/data + * You can encode a string by calling QRcode_encodeString(). + * The given string is parsed automatically and encoded. If you want to encode + * data that can be represented as a C string style (NUL terminated), you can + * simply use this way. + * + * If the input data contains Kanji (Shift-JIS) characters and you want to + * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint. + * Otherwise, all of non-alphanumeric characters are encoded as 8-bit data. + * If you want to encode a whole string in 8-bit mode, you can use + * QRcode_encodeString8bit() instead. + * + * Please note that a C string can not contain NUL characters. If your data + * contains NUL, you must use QRcode_encodeData(). + * + * \subsection encoding-input Encoding a structured data + * You can construct a structured input data manually. If the structure of the + * input data is known, you can use this method. + * At first, create a ::QRinput object by QRinput_new(). Then add input data + * to the QRinput object by QRinput_append(). Finally call QRcode_encodeInput() + * to encode the QRinput data. + * You can reuse the QRinput object again to encode it in other symbols with + * different parameters. + * + * \section result Result + * The encoded symbol is generated as a ::QRcode object. It will contain its + * version number, the width of the symbol, and an array represents the symbol. + * See ::QRcode for the details. You can free the object by QRcode_free(). + * + * Please note that the version of the result may be larger than specified. + * In such cases, the input data would be too large to be encoded in a + * symbol of the specified version. + * + * The following code snippet demonstrates how to use the obtained object: + * + * \code + * QRcode *qrcode; + * + * qrcode = QRcode_encodeString("TEST", 0, QR_ECLEVEL_M, QR_MODE_8, 1); + * if(qrcode == NULL) abort(); + * + * for(int y = 0; y < qrcode->width; y++) { + * for(int x = 0; x < qrcode->width; x++) { + * if(qrcode->data[y * qrcode->width + x] & 1) { + * draw_black_dot(x, y); + * } else { + * draw_white_dot(x, y); + * } + * } + * } + * + * QRcode_free(qrcode); + * \endcode + * + * \section structured Structured append + * Libqrencode can generate "Structured-appended" symbols that enable to split + * a large data set into multiple QR codes. A QR code reader concatenates + * multiple QR code symbols into a string. + * Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured() + * to generate structured-appended symbols. This function returns an instance + * of ::QRcode_List. The returned list is a singly-linked list of QRcode: you + * can retrieve each QR code in this way: + * + * \code + * QRcode_List *qrcodes; + * QRcode_List *entry; + * QRcode *qrcode; + * + * qrcodes = QRcode_encodeStringStructured(...); + * entry = qrcodes; + * while(entry != NULL) { + * qrcode = entry->code; + * // do something + * entry = entry->next; + * } + * QRcode_List_free(entry); + * \endcode + * + * Instead of using auto-parsing functions, you can construct your own + * structured input. At first, instantiate an object of ::QRinput_Struct + * by calling QRinput_Struct_new(). This object can hold multiple ::QRinput, + * and one QR code is generated for a ::QRinput. + * QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct + * object. In order to generate structured-appended symbols, it is required to + * embed headers to each symbol. You can use + * QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate + * headers to each symbol. You should call this function just once before + * encoding symbols. + */ + +#ifndef QRENCODE_H +#define QRENCODE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encoding mode. + */ +typedef enum { + QR_MODE_NUL = -1, ///< Terminator (NUL character). Internal use only + QR_MODE_NUM = 0, ///< Numeric mode + QR_MODE_AN, ///< Alphabet-numeric mode + QR_MODE_8, ///< 8-bit data mode + QR_MODE_KANJI, ///< Kanji (shift-jis) mode + QR_MODE_STRUCTURE, ///< Internal use only + QR_MODE_ECI, ///< ECI mode + QR_MODE_FNC1FIRST, ///< FNC1, first position + QR_MODE_FNC1SECOND, ///< FNC1, second position +} QRencodeMode; + +/** + * Level of error correction. + */ +typedef enum { + QR_ECLEVEL_L = 0, ///< lowest + QR_ECLEVEL_M, + QR_ECLEVEL_Q, + QR_ECLEVEL_H ///< highest +} QRecLevel; + +/** + * Maximum version (size) of QR-code symbol. + */ +#define QRSPEC_VERSION_MAX 40 + +/** + * Maximum version (size) of QR-code symbol. + */ +#define MQRSPEC_VERSION_MAX 4 + + +/****************************************************************************** + * Input data (qrinput.c) + *****************************************************************************/ + +/** + * Singly linked list to contain input strings. An instance of this class + * contains its version and error correction level too. It is required to + * set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(), + * or use QRinput_new2() to instantiate an object. + */ +typedef struct _QRinput QRinput; + +/** + * Instantiate an input data object. The version is set to 0 (auto-select) + * and the error correction level is set to QR_ECLEVEL_L. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput *QRinput_new(void); + +/** + * Instantiate an input data object. + * @param version version number. + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_new2(int version, QRecLevel level); + +/** + * Instantiate an input data object. Object's Micro QR Code flag is set. + * Unlike with full-sized QR Code, version number must be specified (>0). + * @param version version number (1--4). + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_newMQR(int version, QRecLevel level); + +/** + * Append data to an input object. + * The data is copied and appended to the input object. + * @param input input object. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data); + +/** + * Append ECI header. + * @param input input object. + * @param ecinum ECI indicator number (0 - 999999) + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_appendECIheader(QRinput *input, unsigned int ecinum); + +/** + * Get current version. + * @param input input object. + * @return current version. + */ +extern int QRinput_getVersion(QRinput *input); + +/** + * Set version of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersion(QRinput *input, int version); + +/** + * Get current error correction level. + * @param input input object. + * @return Current error correcntion level. + */ +extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input); + +/** + * Set error correction level of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level); + +/** + * Set version and error correction level of the QR code at once. + * This function is recommened for Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level); + +/** + * Free the input object. + * All of data chunks in the input object are freed too. + * @param input input object. + */ +extern void QRinput_free(QRinput *input); + +/** + * Validate the input data. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 invalid arguments. + */ +extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data); + +/** + * Set of QRinput for structured symbols. + */ +typedef struct _QRinput_Struct QRinput_Struct; + +/** + * Instantiate a set of input data object. + * @return an instance of QRinput_Struct. On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_Struct_new(void); + +/** + * Set parity of structured symbols. + * @param s structured input object. + * @param parity parity of s. + */ +extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity); + +/** + * Append a QRinput object to the set. QRinput created by QRinput_newMQR() + * will be rejected. + * @warning never append the same QRinput object twice or more. + * @param s structured input object. + * @param input an input object. + * @retval >0 number of input objects in the structure. + * @retval -1 an error occurred. See Exceptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid arguments. + */ +extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input); + +/** + * Free all of QRinput in the set. + * @param s a structured input object. + */ +extern void QRinput_Struct_free(QRinput_Struct *s); + +/** + * Split a QRinput to QRinput_Struct. It calculates a parity, set it, then + * insert structured-append headers. QRinput created by QRinput_newMQR() will + * be rejected. + * @param input input object. Version number and error correction level must be + * set. + * @return a set of input data. On error, NULL is returned, and errno is set + * to indicate the error. See Exceptions for the details. + * @throw ERANGE input data is too large. + * @throw EINVAL invalid input data. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input); + +/** + * Insert structured-append headers to the input structure. It calculates + * a parity and set it if the parity is not set yet. + * @param s input structure + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory. + */ +extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s); + +/** + * Set FNC1-1st position flag. + */ +extern int QRinput_setFNC1First(QRinput *input); + +/** + * Set FNC1-2nd position flag and application identifier. + */ +extern int QRinput_setFNC1Second(QRinput *input, unsigned char appid); + +/****************************************************************************** + * QRcode output (qrencode.c) + *****************************************************************************/ + +/** + * QRcode class. + * Symbol data is represented as an array contains width*width uchars. + * Each uchar represents a module (dot). If the less significant bit of + * the uchar is 1, the corresponding module is black. The other bits are + * meaningless for usual applications, but here its specification is described. + * + * @verbatim + MSB 76543210 LSB + |||||||`- 1=black/0=white + ||||||`-- 1=ecc/0=data code area + |||||`--- format information + ||||`---- version information + |||`----- timing pattern + ||`------ alignment pattern + |`------- finder pattern and separator + `-------- non-data modules (format, timing, etc.) + @endverbatim + * + * See \ref result section for a sample code snippet that shows how to use the + * obtained QRcode object. + */ +typedef struct { + int version; ///< version of the symbol + int width; ///< width of the symbol + unsigned char *data; ///< symbol data +} QRcode; + +/** + * Singly-linked list of QRcode. Used to represent a structured symbols. + * A list is terminated with NULL. + */ +typedef struct _QRcode_List { + QRcode *code; + struct _QRcode_List *next; +} QRcode_List; + +/** + * Create a symbol from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param input input data. + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode *QRcode_encodeInput(QRinput *input); + +/** + * Create a symbol from the string. The library automatically parses the input + * string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeString(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeString(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Micro QR Code version of QRcode_encodeString8bit(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level); + +/** + * Encode byte stream (may include '\0') in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input data. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeData(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Free the instance of QRcode class. + * @param qrcode an instance of QRcode class. + */ +extern void QRcode_free(QRcode *qrcode); + +/** + * Create structured symbols from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param s input data, structured. + * @return a singly-linked list of QRcode. + */ +extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s); + +/** + * Create structured symbols from the string. The library automatically parses + * the input string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeStringStructured(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level); + +/** + * Create structured symbols from byte stream (may include '\0'). Wholde data + * are encoded in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input dat. + * @param version version of the symbol. + * @param level error correction level. + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Return the number of symbols included in a QRcode_List. + * @param qrlist a head entry of a QRcode_List. + * @return number of symbols in the list. + */ +extern int QRcode_List_size(QRcode_List *qrlist); + +/** + * Free the QRcode_List. + * @param qrlist a head entry of a QRcode_List. + */ +extern void QRcode_List_free(QRcode_List *qrlist); + + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +/** + * Return the major.minor.micro version numbers that identifies the + * library version. + * @param major_version a pointer where to store the major version number + * @param minor_version a pointer where to store the minor version number + * @param micro_version a pointer where to store the micro version number + */ +extern void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version); + +/** + * Return a string that identifies the library version. + * @return a string identifies the library version. The string is held by the + * library. Do NOT free it. + */ +extern char *QRcode_APIVersionString(void); + +/** + * @deprecated + */ +#ifndef _MSC_VER +extern void QRcode_clearCache(void) __attribute__ ((deprecated)); +#else +extern void QRcode_clearCache(void); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* QRENCODE_H */ diff --git a/genqrcode/qrencode_inner.h b/genqrcode/qrencode_inner.h new file mode 100644 index 0000000000..2ea54f59d0 --- /dev/null +++ b/genqrcode/qrencode_inner.h @@ -0,0 +1,88 @@ +/** + * qrencode - QR Code encoder + * + * Header for test use + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QRENCODE_INNER_H +#define QRENCODE_INNER_H + +/** + * This header file includes definitions for test use. + */ + +/****************************************************************************** + * Raw code + *****************************************************************************/ + +typedef struct { + int dataLength; + int eccLength; + unsigned char *data; + unsigned char *ecc; +} RSblock; + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + int b1; + int blocks; + RSblock *rsblock; + int count; +} QRRawCode; + +extern QRRawCode *QRraw_new(QRinput *input); +extern unsigned char QRraw_getCode(QRRawCode *raw); +extern void QRraw_free(QRRawCode *raw); + +/****************************************************************************** + * Raw code for Micro QR Code + *****************************************************************************/ + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + RSblock *rsblock; + int oddbits; + int count; +} MQRRawCode; + +extern MQRRawCode *MQRraw_new(QRinput *input); +extern unsigned char MQRraw_getCode(MQRRawCode *raw); +extern void MQRraw_free(MQRRawCode *raw); + +/****************************************************************************** + * Frame filling + *****************************************************************************/ +extern unsigned char *FrameFiller_test(int version); +extern unsigned char *FrameFiller_testMQR(int version); + +/****************************************************************************** + * QR-code encoding + *****************************************************************************/ +extern QRcode *QRcode_encodeMask(QRinput *input, int mask); +extern QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask); +extern QRcode *QRcode_new(int version, int width, unsigned char *data); + +#endif /* QRENCODE_INNER_H */ diff --git a/genqrcode/qrinput.c b/genqrcode/qrinput.c new file mode 100644 index 0000000000..266b586dc2 --- /dev/null +++ b/genqrcode/qrinput.c @@ -0,0 +1,1639 @@ +/* + * qrencode - QR Code encoder + * + * Input data chunk class + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "qrencode.h" +#include "qrspec.h" +#include "mqrspec.h" +#include "bitstream.h" +#include "qrinput.h" + +/****************************************************************************** + * Utilities + *****************************************************************************/ +int QRinput_isSplittableMode(QRencodeMode mode) +{ + return (mode >= QR_MODE_NUM && mode <= QR_MODE_KANJI); +} + +/****************************************************************************** + * Entry of input data + *****************************************************************************/ + +static QRinput_List *QRinput_List_newEntry(QRencodeMode mode, int size, const unsigned char *data) +{ + QRinput_List *entry; + + if(QRinput_check(mode, size, data)) { + errno = EINVAL; + return NULL; + } + + entry = (QRinput_List *)malloc(sizeof(QRinput_List)); + if(entry == NULL) return NULL; + + entry->mode = mode; + entry->size = size; + entry->data = NULL; + if(size > 0) { + entry->data = (unsigned char *)malloc((size_t)size); + if(entry->data == NULL) { + free(entry); + return NULL; + } + memcpy(entry->data, data, (size_t)size); + } + entry->bstream = NULL; + entry->next = NULL; + + return entry; +} + +static void QRinput_List_freeEntry(QRinput_List *entry) +{ + if(entry != NULL) { + free(entry->data); + BitStream_free(entry->bstream); + free(entry); + } +} + +static QRinput_List *QRinput_List_dup(QRinput_List *entry) +{ + QRinput_List *n; + + n = (QRinput_List *)malloc(sizeof(QRinput_List)); + if(n == NULL) return NULL; + + n->mode = entry->mode; + n->size = entry->size; + n->data = (unsigned char *)malloc((size_t)n->size); + if(n->data == NULL) { + free(n); + return NULL; + } + memcpy(n->data, entry->data, (size_t)entry->size); + n->bstream = NULL; + n->next = NULL; + + return n; +} + +/****************************************************************************** + * Input Data + *****************************************************************************/ + +QRinput *QRinput_new(void) +{ + return QRinput_new2(0, QR_ECLEVEL_L); +} + +QRinput *QRinput_new2(int version, QRecLevel level) +{ + QRinput *input; + + if(version < 0 || version > QRSPEC_VERSION_MAX || level < 0 || level > QR_ECLEVEL_H) { + errno = EINVAL; + return NULL; + } + + input = (QRinput *)malloc(sizeof(QRinput)); + if(input == NULL) return NULL; + + input->head = NULL; + input->tail = NULL; + input->version = version; + input->level = level; + input->mqr = 0; + input->fnc1 = 0; + + return input; +} + +QRinput *QRinput_newMQR(int version, QRecLevel level) +{ + QRinput *input; + + if(version <= 0 || version > MQRSPEC_VERSION_MAX) goto INVALID; + if(MQRspec_getECCLength(version, level) == 0) goto INVALID; + + input = QRinput_new2(version, level); + if(input == NULL) return NULL; + + input->mqr = 1; + + return input; + +INVALID: + errno = EINVAL; + return NULL; +} + +int QRinput_getVersion(QRinput *input) +{ + return input->version; +} + +int QRinput_setVersion(QRinput *input, int version) +{ + if(input->mqr || version < 0 || version > QRSPEC_VERSION_MAX) { + errno = EINVAL; + return -1; + } + + input->version = version; + + return 0; +} + +QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input) +{ + return input->level; +} + +int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level) +{ + if(input->mqr || level > QR_ECLEVEL_H) { + errno = EINVAL; + return -1; + } + + input->level = level; + + return 0; +} + +int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level) +{ + if(input->mqr) { + if(version <= 0 || version > MQRSPEC_VERSION_MAX) goto INVALID; + if(MQRspec_getECCLength(version, level) == 0) goto INVALID; + } else { + if(version < 0 || version > QRSPEC_VERSION_MAX) goto INVALID; + if(level > QR_ECLEVEL_H) goto INVALID; + } + + input->version = version; + input->level = level; + + return 0; + +INVALID: + errno = EINVAL; + return -1; +} + +static void QRinput_appendEntry(QRinput *input, QRinput_List *entry) +{ + if(input->tail == NULL) { + input->head = entry; + input->tail = entry; + } else { + input->tail->next = entry; + input->tail = entry; + } + entry->next = NULL; +} + +int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data) +{ + QRinput_List *entry; + + entry = QRinput_List_newEntry(mode, size, data); + if(entry == NULL) { + return -1; + } + + QRinput_appendEntry(input, entry); + + return 0; +} + +/** + * Insert a structured-append header to the head of the input data. + * @param input input data. + * @param size number of structured symbols. + * @param number index number of the symbol. (1 <= number <= size) + * @param parity parity among input data. (NOTE: each symbol of a set of structured symbols has the same parity data) + * @retval 0 success. + * @retval -1 error occurred and errno is set to indicate the error. See Execptions for the details. + * @throw EINVAL invalid parameter. + * @throw ENOMEM unable to allocate memory. + */ +STATIC_IN_RELEASE int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int number, int parity) +{ + QRinput_List *entry; + unsigned char buf[3]; + + if(size > MAX_STRUCTURED_SYMBOLS) { + errno = EINVAL; + return -1; + } + if(number <= 0 || number > size) { + errno = EINVAL; + return -1; + } + + buf[0] = (unsigned char)size; + buf[1] = (unsigned char)number; + buf[2] = (unsigned char)parity; + entry = QRinput_List_newEntry(QR_MODE_STRUCTURE, 3, buf); + if(entry == NULL) { + return -1; + } + + entry->next = input->head; + input->head = entry; + + return 0; +} + +int QRinput_appendECIheader(QRinput *input, unsigned int ecinum) +{ + unsigned char data[4]; + + if(ecinum > 999999) { + errno = EINVAL; + return -1; + } + + /* We manually create byte array of ecinum because + (unsigned char *)&ecinum may cause bus error on some architectures, */ + data[0] = ecinum & 0xff; + data[1] = (ecinum >> 8) & 0xff; + data[2] = (ecinum >> 16) & 0xff; + data[3] = (ecinum >> 24) & 0xff; + return QRinput_append(input, QR_MODE_ECI, 4, data); +} + +void QRinput_free(QRinput *input) +{ + QRinput_List *list, *next; + + if(input != NULL) { + list = input->head; + while(list != NULL) { + next = list->next; + QRinput_List_freeEntry(list); + list = next; + } + free(input); + } +} + +static unsigned char QRinput_calcParity(QRinput *input) +{ + unsigned char parity = 0; + QRinput_List *list; + int i; + + list = input->head; + while(list != NULL) { + if(list->mode != QR_MODE_STRUCTURE) { + for(i = list->size-1; i >= 0; i--) { + parity ^= list->data[i]; + } + } + list = list->next; + } + + return parity; +} + +QRinput *QRinput_dup(QRinput *input) +{ + QRinput *n; + QRinput_List *list, *e; + + if(input->mqr) { + n = QRinput_newMQR(input->version, input->level); + } else { + n = QRinput_new2(input->version, input->level); + } + if(n == NULL) return NULL; + + list = input->head; + while(list != NULL) { + e = QRinput_List_dup(list); + if(e == NULL) { + QRinput_free(n); + return NULL; + } + QRinput_appendEntry(n, e); + list = list->next; + } + + return n; +} + +/****************************************************************************** + * Numeric data + *****************************************************************************/ + +/** + * Check the input data. + * @param size size of the input data. + * @param data input data. + * @return result + */ +static int QRinput_checkModeNum(int size, const char *data) +{ + int i; + + for(i = 0; i < size; i++) { + if(data[i] < '0' || data[i] > '9') + return -1; + } + + return 0; +} + +/** + * Estimate the length of the encoded bit stream of numeric data. + * @param size size of the input data. + * @return number of bits + */ +int QRinput_estimateBitsModeNum(int size) +{ + int w; + int bits; + + w = size / 3; + bits = w * 10; + switch(size - w * 3) { + case 1: + bits += 4; + break; + case 2: + bits += 7; + break; + default: + break; + } + + return bits; +} + +/** + * Convert the number data and append to a bit stream. + * @param entry input data. + * @param mqr give 1 if generating Micro QR Code. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_encodeModeNum(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int words, i, ret; + unsigned int val; + + if(mqr) { + if(version > 1) { + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_NUM); + if(ret < 0) return -1; + } + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_NUM, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_NUM); + if(ret < 0) return -1; + + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_NUM, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } + + words = entry->size / 3; + for(i = 0; i < words; i++) { + val = (unsigned int)(entry->data[i*3 ] - '0') * 100; + val += (unsigned int)(entry->data[i*3+1] - '0') * 10; + val += (unsigned int)(entry->data[i*3+2] - '0'); + + ret = BitStream_appendNum(bstream, 10, val); + if(ret < 0) return -1; + } + + if(entry->size - words * 3 == 1) { + val = (unsigned int)(entry->data[words*3] - '0'); + ret = BitStream_appendNum(bstream, 4, val); + if(ret < 0) return -1; + } else if(entry->size - words * 3 == 2) { + val = (unsigned int)(entry->data[words*3 ] - '0') * 10; + val += (unsigned int)(entry->data[words*3+1] - '0'); + ret = BitStream_appendNum(bstream, 7, val); + if(ret < 0) return -1; + } + + return 0; +} + +/****************************************************************************** + * Alphabet-numeric data + *****************************************************************************/ + +const signed char QRinput_anTable[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/** + * Check the input data. + * @param size size of the input data. + * @param data input data. + * @return result + */ +static int QRinput_checkModeAn(int size, const char *data) +{ + int i; + + for(i = 0; i < size; i++) { + if(QRinput_lookAnTable(data[i]) < 0) + return -1; + } + + return 0; +} + +/** + * Estimate the length of the encoded bit stream of alphabet-numeric data. + * @param size size of the input data. + * @return number of bits + */ +int QRinput_estimateBitsModeAn(int size) +{ + int w; + int bits; + + w = size / 2; + bits = w * 11; + if(size & 1) { + bits += 6; + } + + return bits; +} + +/** + * Convert the alphabet-numeric data and append to a bit stream. + * @param entry input data. + * @param mqr give 1 if generating Micro QR Code. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid version. + */ +static int QRinput_encodeModeAn(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int words, i, ret; + unsigned int val; + + if(mqr) { + if(version < 2) { + errno = ERANGE; + return -1; + } + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_AN); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_AN, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_AN); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_AN, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } + + words = entry->size / 2; + for(i = 0; i < words; i++) { + val = (unsigned int)QRinput_lookAnTable(entry->data[i*2 ]) * 45; + val += (unsigned int)QRinput_lookAnTable(entry->data[i*2+1]); + + ret = BitStream_appendNum(bstream, 11, val); + if(ret < 0) return -1; + } + + if(entry->size & 1) { + val = (unsigned int)QRinput_lookAnTable(entry->data[words * 2]); + + ret = BitStream_appendNum(bstream, 6, val); + if(ret < 0) return -1; + } + + return 0; +} + +/****************************************************************************** + * 8 bit data + *****************************************************************************/ + +/** + * Estimate the length of the encoded bit stream of 8 bit data. + * @param size size of the input data. + * @return number of bits + */ +int QRinput_estimateBitsMode8(int size) +{ + return size * 8; +} + +/** + * Convert the 8bits data and append to a bit stream. + * @param entry input data. + * @param mqr give 1 if generating Micro QR Code. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_encodeMode8(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int ret; + + if(mqr) { + if(version < 3) { + errno = ERANGE; + return -1; + } + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_8); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_8, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_8); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_8, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } + + ret = BitStream_appendBytes(bstream, (size_t)entry->size, entry->data); + if(ret < 0) return -1; + + return 0; +} + + +/****************************************************************************** + * Kanji data + *****************************************************************************/ + +/** + * Estimate the length of the encoded bit stream of kanji data. + * @param size size of the input data. + * @return number of bits + */ +int QRinput_estimateBitsModeKanji(int size) +{ + return (size / 2) * 13; +} + +/** + * Check the input data. + * @param size size of the input data. + * @param data input data. + * @return result + */ +static int QRinput_checkModeKanji(int size, const unsigned char *data) +{ + int i; + unsigned int val; + + if(size & 1) + return -1; + + for(i = 0; i < size; i+=2) { + val = ((unsigned int)data[i] << 8) | data[i+1]; + if(val < 0x8140 || (val > 0x9ffc && val < 0xe040) || val > 0xebbf) { + return -1; + } + } + + return 0; +} + +/** + * Convert the kanji data and append to a bit stream. + * @param entry input data. + * @param mqr give 1 if generating Micro QR Code. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid version. + */ +static int QRinput_encodeModeKanji(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int ret, i; + unsigned int val, h; + + if(mqr) { + if(version < 2) { + errno = ERANGE; + return -1; + } + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_KANJI); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_KANJI, version), (unsigned int)entry->size/2); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_KANJI); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_KANJI, version), (unsigned int)entry->size/2); + if(ret < 0) return -1; + } + + for(i = 0; i < entry->size; i+=2) { + val = ((unsigned int)entry->data[i] << 8) | entry->data[i+1]; + if(val <= 0x9ffc) { + val -= 0x8140; + } else { + val -= 0xc140; + } + h = (val >> 8) * 0xc0; + val = (val & 0xff) + h; + + ret = BitStream_appendNum(bstream, 13, val); + if(ret < 0) return -1; + } + + return 0; +} + +/****************************************************************************** + * Structured Symbol + *****************************************************************************/ + +/** + * Convert a structure symbol code and append to a bit stream. + * @param entry input data. + * @param mqr give 1 if generating Micro QR Code. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid entry. + */ +static int QRinput_encodeModeStructure(QRinput_List *entry, BitStream *bstream, int mqr) +{ + int ret; + + if(mqr) { + errno = EINVAL; + return -1; + } + + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_STRUCTURE); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, 4, entry->data[1] - 1U); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, 4, entry->data[0] - 1U); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, 8, entry->data[2]); + if(ret < 0) return -1; + + return 0; +} + +/****************************************************************************** + * FNC1 + *****************************************************************************/ + +static int QRinput_checkModeFNC1Second(int size) +{ + if(size != 1) return -1; + + /* No data check required. */ + + return 0; +} + +static int QRinput_encodeModeFNC1Second(QRinput_List *entry, BitStream *bstream) +{ + int ret; + + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_FNC1SECOND); + if(ret < 0) return -1; + + ret = BitStream_appendBytes(bstream, 1, entry->data); + if(ret < 0) return -1; + + return 0; +} + +/****************************************************************************** + * ECI header + *****************************************************************************/ +static unsigned int QRinput_decodeECIfromByteArray(unsigned char *data) +{ + int i; + unsigned int ecinum; + + ecinum = 0; + for(i = 0; i < 4; i++) { + ecinum = ecinum << 8; + ecinum |= data[3-i]; + } + + return ecinum; +} + +static int QRinput_estimateBitsModeECI(unsigned char *data) +{ + unsigned int ecinum; + + ecinum = QRinput_decodeECIfromByteArray(data); + + /* See Table 4 of JISX 0510:2004 p.17. */ + if(ecinum < 128) { + return MODE_INDICATOR_SIZE + 8; + } else if(ecinum < 16384) { + return MODE_INDICATOR_SIZE + 16; + } else { + return MODE_INDICATOR_SIZE + 24; + } +} + +static int QRinput_encodeModeECI(QRinput_List *entry, BitStream *bstream) +{ + int ret, words; + unsigned int ecinum, code; + + ecinum = QRinput_decodeECIfromByteArray(entry->data); + + /* See Table 4 of JISX 0510:2004 p.17. */ + if(ecinum < 128) { + words = 1; + code = ecinum; + } else if(ecinum < 16384) { + words = 2; + code = 0x8000 + ecinum; + } else { + words = 3; + code = 0xc0000 + ecinum; + } + + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_ECI); + if(ret < 0) return -1; + + ret = BitStream_appendNum(bstream, (size_t)words * 8, code); + if(ret < 0) return -1; + + return 0; +} + +/****************************************************************************** + * Validation + *****************************************************************************/ + +int QRinput_check(QRencodeMode mode, int size, const unsigned char *data) +{ + if((mode == QR_MODE_FNC1FIRST && size < 0) || size <= 0) return -1; + + switch(mode) { + case QR_MODE_NUM: + return QRinput_checkModeNum(size, (const char *)data); + case QR_MODE_AN: + return QRinput_checkModeAn(size, (const char *)data); + case QR_MODE_KANJI: + return QRinput_checkModeKanji(size, data); + case QR_MODE_8: + return 0; + case QR_MODE_STRUCTURE: + return 0; + case QR_MODE_ECI: + return 0; + case QR_MODE_FNC1FIRST: + return 0; + case QR_MODE_FNC1SECOND: + return QRinput_checkModeFNC1Second(size); + case QR_MODE_NUL: + break; + } + + return -1; +} + +/****************************************************************************** + * Estimation of the bit length + *****************************************************************************/ + +/** + * Estimate the length of the encoded bit stream on the current version. + * @param entry input data. + * @param version version of the symbol + * @param mqr give 1 if generating Micro QR Code. + * @return number of bits + */ +static int QRinput_estimateBitStreamSizeOfEntry(QRinput_List *entry, int version, int mqr) +{ + int bits = 0; + int l, m; + int num; + + if(version == 0) version = 1; + + switch(entry->mode) { + case QR_MODE_NUM: + bits = QRinput_estimateBitsModeNum(entry->size); + break; + case QR_MODE_AN: + bits = QRinput_estimateBitsModeAn(entry->size); + break; + case QR_MODE_8: + bits = QRinput_estimateBitsMode8(entry->size); + break; + case QR_MODE_KANJI: + bits = QRinput_estimateBitsModeKanji(entry->size); + break; + case QR_MODE_STRUCTURE: + return STRUCTURE_HEADER_SIZE; + case QR_MODE_ECI: + bits = QRinput_estimateBitsModeECI(entry->data); + break; + case QR_MODE_FNC1FIRST: + return MODE_INDICATOR_SIZE; + case QR_MODE_FNC1SECOND: + return MODE_INDICATOR_SIZE + 8; + default: + return 0; + } + + if(mqr) { + l = MQRspec_lengthIndicator(entry->mode, version); + m = version - 1; + bits += l + m; + } else { + l = QRspec_lengthIndicator(entry->mode, version); + m = 1 << l; + if(entry->mode == QR_MODE_KANJI) { + num = (entry->size/2 + m - 1) / m; + } else { + num = (entry->size + m - 1) / m; + } + + bits += num * (MODE_INDICATOR_SIZE + l); + } + + return bits; +} + +/** + * Estimate the length of the encoded bit stream of the data. + * @param input input data + * @param version version of the symbol + * @return number of bits + */ +STATIC_IN_RELEASE int QRinput_estimateBitStreamSize(QRinput *input, int version) +{ + QRinput_List *list; + int bits = 0; + + list = input->head; + while(list != NULL) { + bits += QRinput_estimateBitStreamSizeOfEntry(list, version, input->mqr); + list = list->next; + } + + return bits; +} + +/** + * Estimate the required version number of the symbol. + * @param input input data + * @return required version number or -1 for failure. + */ +STATIC_IN_RELEASE int QRinput_estimateVersion(QRinput *input) +{ + int bits; + int version, prev; + + version = 0; + do { + prev = version; + bits = QRinput_estimateBitStreamSize(input, prev); + version = QRspec_getMinimumVersion((bits + 7) / 8, input->level); + if(prev == 0 && version > 1) { + version--; + } + } while (version > prev); + + return version; +} + +/** + * Return required length in bytes for specified mode, version and bits. + * @param mode encode mode. + * @param version version of the symbol. + * @param bits length of the input data in bits. + * @return required length of code words in bytes. + */ +STATIC_IN_RELEASE int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits) +{ + int payload, size, chunks, remain, maxsize; + + payload = bits - 4 - QRspec_lengthIndicator(mode, version); + switch(mode) { + case QR_MODE_NUM: + chunks = payload / 10; + remain = payload - chunks * 10; + size = chunks * 3; + if(remain >= 7) { + size += 2; + } else if(remain >= 4) { + size += 1; + } + break; + case QR_MODE_AN: + chunks = payload / 11; + remain = payload - chunks * 11; + size = chunks * 2; + if(remain >= 6) size++; + break; + case QR_MODE_8: + size = payload / 8; + break; + case QR_MODE_KANJI: + size = (payload / 13) * 2; + break; + case QR_MODE_STRUCTURE: + size = payload / 8; + break; + default: + size = 0; + break; + } + maxsize = QRspec_maximumWords(mode, version); + if(size < 0) size = 0; + if(maxsize > 0 && size > maxsize) size = maxsize; + + return size; +} + +/****************************************************************************** + * Data conversion + *****************************************************************************/ + +/** + * Convert the input data in the data chunk and append to a bit stream. + * @param entry input data. + * @param [out] bstream destination BitStream. + * @return number of bits (>0) or -1 for failure. + */ +static int QRinput_encodeBitStream(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int words, ret; + QRinput_List *st1 = NULL, *st2 = NULL; + int prevsize; + + prevsize = (int)BitStream_size(bstream); + + if(mqr) { + words = MQRspec_maximumWords(entry->mode, version); + } else { + words = QRspec_maximumWords(entry->mode, version); + } + if(words != 0 && entry->size > words) { + st1 = QRinput_List_newEntry(entry->mode, words, entry->data); + if(st1 == NULL) goto ABORT; + st2 = QRinput_List_newEntry(entry->mode, entry->size - words, &entry->data[words]); + if(st2 == NULL) goto ABORT; + + ret = QRinput_encodeBitStream(st1, bstream, version, mqr); + if(ret < 0) goto ABORT; + ret = QRinput_encodeBitStream(st2, bstream, version, mqr); + if(ret < 0) goto ABORT; + + QRinput_List_freeEntry(st1); + QRinput_List_freeEntry(st2); + } else { + ret = 0; + switch(entry->mode) { + case QR_MODE_NUM: + ret = QRinput_encodeModeNum(entry, bstream, version, mqr); + break; + case QR_MODE_AN: + ret = QRinput_encodeModeAn(entry, bstream, version, mqr); + break; + case QR_MODE_8: + ret = QRinput_encodeMode8(entry, bstream, version, mqr); + break; + case QR_MODE_KANJI: + ret = QRinput_encodeModeKanji(entry, bstream, version, mqr); + break; + case QR_MODE_STRUCTURE: + ret = QRinput_encodeModeStructure(entry, bstream, mqr); + break; + case QR_MODE_ECI: + ret = QRinput_encodeModeECI(entry, bstream); + break; + case QR_MODE_FNC1SECOND: + ret = QRinput_encodeModeFNC1Second(entry, bstream); + break; + default: + break; + } + if(ret < 0) return -1; + } + + return (int)BitStream_size(bstream) - prevsize; +ABORT: + QRinput_List_freeEntry(st1); + QRinput_List_freeEntry(st2); + return -1; +} + +/** + * Convert the input data to a bit stream. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_createBitStream(QRinput *input, BitStream *bstream) +{ + QRinput_List *list; + int bits, total = 0; + + list = input->head; + while(list != NULL) { + bits = QRinput_encodeBitStream(list, bstream, input->version, input->mqr); + if(bits < 0) return -1; + total += bits; + list = list->next; + } + + return total; +} + +/** + * Convert the input data to a bit stream. + * When the version number is given and that is not sufficient, it is increased + * automatically. + * @param input input data. + * @param bstream Bitstream to be appended. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw ERANGE input data is too large. + */ +static int QRinput_convertData(QRinput *input, BitStream *bstream) +{ + int bits; + int ver; + + ver = QRinput_estimateVersion(input); + if(ver > QRinput_getVersion(input)) { + QRinput_setVersion(input, ver); + } + + for(;;) { + BitStream_reset(bstream); + bits = QRinput_createBitStream(input, bstream); + if(bits < 0) return -1; + ver = QRspec_getMinimumVersion((bits + 7) / 8, input->level); + if(ver > QRinput_getVersion(input)) { + QRinput_setVersion(input, ver); + } else { + break; + } + } + + return 0; +} + +/** + * Append padding bits for the input data. + * @param bstream Bitstream to be appended. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ERANGE input data is too large. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_appendPaddingBit(BitStream *bstream, QRinput *input) +{ + int bits, maxbits, words, maxwords, i, ret; + int padlen; + + bits = (int)BitStream_size(bstream); + maxwords = QRspec_getDataLength(input->version, input->level); + maxbits = maxwords * 8; + + if(maxbits < bits) { + errno = ERANGE; + return -1; + } + if(maxbits == bits) { + return 0; + } + + if(maxbits - bits <= 4) { + return (int)BitStream_appendNum(bstream, (size_t)(maxbits - bits), 0); + } + + words = (bits + 4 + 7) / 8; + + ret = (int)BitStream_appendNum(bstream, (size_t)(words * 8 - bits), 0); + if(ret < 0) return ret; + + padlen = maxwords - words; + if(padlen > 0) { + for(i = 0; i < padlen; i++) { + ret = (int)BitStream_appendNum(bstream, 8, (i&1)?0x11:0xec); + if(ret < 0) { + return ret; + } + } + } + + return 0; +} + +/** + * Append padding bits for the input data - Micro QR Code version. + * @param bstream Bitstream to be appended. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indicate the error. + * See Execptions for the details. + * @throw ERANGE input data is too large. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_appendPaddingBitMQR(BitStream *bstream, QRinput *input) +{ + int bits, maxbits, words, maxwords, i, ret, termbits; + int padlen; + + bits = (int)BitStream_size(bstream); + maxbits = MQRspec_getDataLengthBit(input->version, input->level); + maxwords = maxbits / 8; + + if(maxbits < bits) { + errno = ERANGE; + return -1; + } + if(maxbits == bits) { + return 0; + } + + termbits = input->version * 2 + 1; + + if(maxbits - bits <= termbits) { + return (int)BitStream_appendNum(bstream, (size_t)(maxbits - bits), 0); + } + + bits += termbits; + + words = (bits + 7) / 8; + if(maxbits - words * 8 > 0) { + termbits += words * 8 - bits; + if(words == maxwords) termbits += maxbits - words * 8; + } else { + termbits += words * 8 - bits; + } + ret = (int)BitStream_appendNum(bstream, (size_t)termbits, 0); + if(ret < 0) return ret; + + padlen = maxwords - words; + if(padlen > 0) { + for(i = 0; i < padlen; i++) { + ret = (int)BitStream_appendNum(bstream, 8, (i&1)?0x11:0xec); + if(ret < 0) return ret; + } + termbits = maxbits - maxwords * 8; + if(termbits > 0) { + ret = (int)BitStream_appendNum(bstream, (size_t)termbits, 0); + if(ret < 0) return ret; + } + } + + return 0; +} + +static int QRinput_insertFNC1Header(QRinput *input) +{ + QRinput_List *entry = NULL; + + if(input->fnc1 == 1) { + entry = QRinput_List_newEntry(QR_MODE_FNC1FIRST, 0, NULL); + } else if(input->fnc1 == 2) { + entry = QRinput_List_newEntry(QR_MODE_FNC1SECOND, 1, &(input->appid)); + } + if(entry == NULL) { + return -1; + } + + if(input->head->mode != QR_MODE_STRUCTURE && input->head->mode != QR_MODE_ECI) { + entry->next = input->head; + input->head = entry; + } else { + entry->next = input->head->next; + input->head->next = entry; + } + + return 0; +} + +/** + * Merge all bit streams in the input data. + * @param input input data. + * @return merged bit stream + */ + +STATIC_IN_RELEASE int QRinput_mergeBitStream(QRinput *input, BitStream *bstream) +{ + if(input->mqr) { + if(QRinput_createBitStream(input, bstream) < 0) { + return -1; + } + } else { + if(input->fnc1) { + if(QRinput_insertFNC1Header(input) < 0) { + return -1; + } + } + if(QRinput_convertData(input, bstream) < 0) { + return -1; + } + } + + return 0; +} + +/** + * Merge all bit streams in the input data and append padding bits + * @param input input data. + * @return padded merged bit stream + */ + +STATIC_IN_RELEASE int QRinput_getBitStream(QRinput *input, BitStream *bstream) +{ + int ret; + + ret = QRinput_mergeBitStream(input, bstream); + if(ret < 0) return -1; + + if(input->mqr) { + ret = QRinput_appendPaddingBitMQR(bstream, input); + } else { + ret = QRinput_appendPaddingBit(bstream, input); + } + if(ret < 0) return -1; + + return 0; +} + +/** + * Pack all bit streams padding bits into a byte array. + * @param input input data. + * @return padded merged byte stream + */ + +unsigned char *QRinput_getByteStream(QRinput *input) +{ + BitStream *bstream; + unsigned char *array; + int ret; + + bstream = BitStream_new(); + if(bstream == NULL) { + return NULL; + } + + ret = QRinput_getBitStream(input, bstream); + if(ret < 0) { + BitStream_free(bstream); + return NULL; + } + array = BitStream_toByte(bstream); + BitStream_free(bstream); + + return array; +} + +/****************************************************************************** + * Structured input data + *****************************************************************************/ + +static QRinput_InputList *QRinput_InputList_newEntry(QRinput *input) +{ + QRinput_InputList *entry; + + entry = (QRinput_InputList *)malloc(sizeof(QRinput_InputList)); + if(entry == NULL) return NULL; + + entry->input = input; + entry->next = NULL; + + return entry; +} + +static void QRinput_InputList_freeEntry(QRinput_InputList *entry) +{ + if(entry != NULL) { + QRinput_free(entry->input); + free(entry); + } +} + +QRinput_Struct *QRinput_Struct_new(void) +{ + QRinput_Struct *s; + + s = (QRinput_Struct *)malloc(sizeof(QRinput_Struct)); + if(s == NULL) return NULL; + + s->size = 0; + s->parity = -1; + s->head = NULL; + s->tail = NULL; + + return s; +} + +void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity) +{ + s->parity = (int)parity; +} + +int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input) +{ + QRinput_InputList *e; + + if(input->mqr) { + errno = EINVAL; + return -1; + } + + e = QRinput_InputList_newEntry(input); + if(e == NULL) return -1; + + s->size++; + if(s->tail == NULL) { + s->head = e; + s->tail = e; + } else { + s->tail->next = e; + s->tail = e; + } + + return s->size; +} + +void QRinput_Struct_free(QRinput_Struct *s) +{ + QRinput_InputList *list, *next; + + if(s != NULL) { + list = s->head; + while(list != NULL) { + next = list->next; + QRinput_InputList_freeEntry(list); + list = next; + } + free(s); + } +} + +static unsigned char QRinput_Struct_calcParity(QRinput_Struct *s) +{ + QRinput_InputList *list; + unsigned char parity = 0; + + list = s->head; + while(list != NULL) { + parity ^= QRinput_calcParity(list->input); + list = list->next; + } + + QRinput_Struct_setParity(s, parity); + + return parity; +} + +static int QRinput_List_shrinkEntry(QRinput_List *entry, int bytes) +{ + unsigned char *data; + + data = (unsigned char *)malloc((size_t)bytes); + if(data == NULL) return -1; + + memcpy(data, entry->data, (size_t)bytes); + free(entry->data); + entry->data = data; + entry->size = bytes; + + return 0; +} + +STATIC_IN_RELEASE int QRinput_splitEntry(QRinput_List *entry, int bytes) +{ + QRinput_List *e; + int ret; + + e = QRinput_List_newEntry(entry->mode, entry->size - bytes, entry->data + bytes); + if(e == NULL) { + return -1; + } + + ret = QRinput_List_shrinkEntry(entry, bytes); + if(ret < 0) { + QRinput_List_freeEntry(e); + return -1; + } + + e->next = entry->next; + entry->next = e; + + return 0; +} + +QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input) +{ + QRinput *p = NULL; + QRinput_Struct *s = NULL; + int bits, maxbits, nextbits, bytes, ret; + QRinput_List *list, *next, *prev; + BitStream *bstream = NULL; + + if(input->mqr) { + errno = EINVAL; + return NULL; + } + + s = QRinput_Struct_new(); + if(s == NULL) return NULL; + + input = QRinput_dup(input); + if(input == NULL) { + QRinput_Struct_free(s); + return NULL; + } + + QRinput_Struct_setParity(s, QRinput_calcParity(input)); + maxbits = QRspec_getDataLength(input->version, input->level) * 8 - STRUCTURE_HEADER_SIZE; + + if(maxbits <= 0) goto ABORT; + + bstream = BitStream_new(); + if(bstream == NULL) goto ABORT; + + bits = 0; + list = input->head; + prev = NULL; + while(list != NULL) { + nextbits = QRinput_estimateBitStreamSizeOfEntry(list, input->version, input->mqr); + if(bits + nextbits <= maxbits) { + BitStream_reset(bstream); + ret = QRinput_encodeBitStream(list, bstream, input->version, input->mqr); + if(ret < 0) goto ABORT; + bits += ret; + prev = list; + list = list->next; + } else { + bytes = QRinput_lengthOfCode(list->mode, input->version, maxbits - bits); + p = QRinput_new2(input->version, input->level); + if(p == NULL) goto ABORT; + if(bytes > 0) { + /* Splits this entry into 2 entries. */ + ret = QRinput_splitEntry(list, bytes); + if(ret < 0) { + QRinput_free(p); + goto ABORT; + } + /* First half is the tail of the current input. */ + next = list->next; + list->next = NULL; + /* Second half is the head of the next input, p.*/ + p->head = next; + /* Renew QRinput.tail. */ + p->tail = input->tail; + input->tail = list; + /* Point to the next entry. */ + prev = list; + list = next; + } else { + /* Current entry will go to the next input. */ + prev->next = NULL; + p->head = list; + p->tail = input->tail; + input->tail = prev; + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) { + QRinput_free(p); + goto ABORT; + } + input = p; + bits = 0; + } + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) goto ABORT; + if(s->size > MAX_STRUCTURED_SYMBOLS) { + errno = ERANGE; + QRinput_Struct_free(s); + BitStream_free(bstream); + return NULL; + } + ret = QRinput_Struct_insertStructuredAppendHeaders(s); + if(ret < 0) { + QRinput_Struct_free(s); + BitStream_free(bstream); + return NULL; + } + + BitStream_free(bstream); + return s; + +ABORT: + BitStream_free(bstream); + QRinput_free(input); + QRinput_Struct_free(s); + return NULL; +} + +int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s) +{ + int i; + QRinput_InputList *list; + + if(s->size == 1) { + return 0; + } + + if(s->parity < 0) { + QRinput_Struct_calcParity(s); + } + i = 1; + list = s->head; + while(list != NULL) { + if(QRinput_insertStructuredAppendHeader(list->input, s->size, i, s->parity)) + return -1; + i++; + list = list->next; + } + + return 0; +} + +/****************************************************************************** + * Extended encoding mode (FNC1 and ECI) + *****************************************************************************/ + +int QRinput_setFNC1First(QRinput *input) +{ + if(input->mqr) { + errno = EINVAL; + return -1; + } + input->fnc1 = 1; + + return 0; +} + +int QRinput_setFNC1Second(QRinput *input, unsigned char appid) +{ + if(input->mqr) { + errno = EINVAL; + return -1; + } + input->fnc1 = 2; + input->appid = appid; + + return 0; +} diff --git a/genqrcode/qrinput.h b/genqrcode/qrinput.h new file mode 100644 index 0000000000..d1d3b25977 --- /dev/null +++ b/genqrcode/qrinput.h @@ -0,0 +1,124 @@ +/* + * qrencode - QR Code encoder + * + * Input data chunk class + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QRINPUT_H +#define QRINPUT_H + +#include "qrencode.h" +#include "bitstream.h" + +int QRinput_isSplittableMode(QRencodeMode mode); + +/****************************************************************************** + * Entry of input data + *****************************************************************************/ +typedef struct _QRinput_List QRinput_List; + +struct _QRinput_List { + QRencodeMode mode; + int size; ///< Size of data chunk (byte). + unsigned char *data; ///< Data chunk. + BitStream *bstream; + QRinput_List *next; +}; + +/****************************************************************************** + * Input Data + *****************************************************************************/ +struct _QRinput { + int version; + QRecLevel level; + QRinput_List *head; + QRinput_List *tail; + int mqr; + int fnc1; + unsigned char appid; +}; + +/****************************************************************************** + * Structured append input data + *****************************************************************************/ +typedef struct _QRinput_InputList QRinput_InputList; + +struct _QRinput_InputList { + QRinput *input; + QRinput_InputList *next; +}; + +struct _QRinput_Struct { + int size; ///< number of structured symbols + int parity; + QRinput_InputList *head; + QRinput_InputList *tail; +}; + +/** + * Pack all bit streams padding bits into a byte array. + * @param input input data. + * @return padded merged byte stream + */ +extern unsigned char *QRinput_getByteStream(QRinput *input); + + +extern int QRinput_estimateBitsModeNum(int size); +extern int QRinput_estimateBitsModeAn(int size); +extern int QRinput_estimateBitsMode8(int size); +extern int QRinput_estimateBitsModeKanji(int size); + +extern QRinput *QRinput_dup(QRinput *input); + +extern const signed char QRinput_anTable[128]; + +/** + * Look up the alphabet-numeric convesion table (see JIS X0510:2004, p.19). + * @param __c__ character + * @return value + */ +#define QRinput_lookAnTable(__c__) \ + ((__c__ & 0x80)?-1:QRinput_anTable[(int)__c__]) + +/** + * Length of a standard mode indicator in bits. + */ + +#define MODE_INDICATOR_SIZE 4 + +/** + * Length of a segment of structured-append header. + */ +#define STRUCTURE_HEADER_SIZE 20 + +/** + * Maximum number of symbols in a set of structured-appended symbols. + */ +#define MAX_STRUCTURED_SYMBOLS 16 + +#ifdef WITH_TESTS +extern int QRinput_mergeBitStream(QRinput *input, BitStream *bstream); +extern int QRinput_getBitStream(QRinput *input, BitStream *bstream); +extern int QRinput_estimateBitStreamSize(QRinput *input, int version); +extern int QRinput_splitEntry(QRinput_List *entry, int bytes); +extern int QRinput_estimateVersion(QRinput *input); +extern int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits); +extern int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, int parity); +#endif + +#endif /* QRINPUT_H */ diff --git a/genqrcode/qrspec.c b/genqrcode/qrspec.c new file mode 100644 index 0000000000..1232c0e0be --- /dev/null +++ b/genqrcode/qrspec.c @@ -0,0 +1,514 @@ +/* + * qrencode - QR Code encoder + * + * QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "qrspec.h" +#include "qrinput.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +typedef struct { + int width; ///< Edge length of the symbol + int words; ///< Data capacity (bytes) + int remainder; ///< Remainder bit (bits) + int ec[4]; ///< Number of ECC code (bytes) +} QRspec_Capacity; + +/** + * Table of the capacity of symbols + * See Table 1 (p.13) and Table 12-16 (pp.30-36), JIS X0510:2004. + */ +static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = { + { 0, 0, 0, { 0, 0, 0, 0}}, + { 21, 26, 0, { 7, 10, 13, 17}}, // 1 + { 25, 44, 7, { 10, 16, 22, 28}}, + { 29, 70, 7, { 15, 26, 36, 44}}, + { 33, 100, 7, { 20, 36, 52, 64}}, + { 37, 134, 7, { 26, 48, 72, 88}}, // 5 + { 41, 172, 7, { 36, 64, 96, 112}}, + { 45, 196, 0, { 40, 72, 108, 130}}, + { 49, 242, 0, { 48, 88, 132, 156}}, + { 53, 292, 0, { 60, 110, 160, 192}}, + { 57, 346, 0, { 72, 130, 192, 224}}, //10 + { 61, 404, 0, { 80, 150, 224, 264}}, + { 65, 466, 0, { 96, 176, 260, 308}}, + { 69, 532, 0, { 104, 198, 288, 352}}, + { 73, 581, 3, { 120, 216, 320, 384}}, + { 77, 655, 3, { 132, 240, 360, 432}}, //15 + { 81, 733, 3, { 144, 280, 408, 480}}, + { 85, 815, 3, { 168, 308, 448, 532}}, + { 89, 901, 3, { 180, 338, 504, 588}}, + { 93, 991, 3, { 196, 364, 546, 650}}, + { 97, 1085, 3, { 224, 416, 600, 700}}, //20 + {101, 1156, 4, { 224, 442, 644, 750}}, + {105, 1258, 4, { 252, 476, 690, 816}}, + {109, 1364, 4, { 270, 504, 750, 900}}, + {113, 1474, 4, { 300, 560, 810, 960}}, + {117, 1588, 4, { 312, 588, 870, 1050}}, //25 + {121, 1706, 4, { 336, 644, 952, 1110}}, + {125, 1828, 4, { 360, 700, 1020, 1200}}, + {129, 1921, 3, { 390, 728, 1050, 1260}}, + {133, 2051, 3, { 420, 784, 1140, 1350}}, + {137, 2185, 3, { 450, 812, 1200, 1440}}, //30 + {141, 2323, 3, { 480, 868, 1290, 1530}}, + {145, 2465, 3, { 510, 924, 1350, 1620}}, + {149, 2611, 3, { 540, 980, 1440, 1710}}, + {153, 2761, 3, { 570, 1036, 1530, 1800}}, + {157, 2876, 0, { 570, 1064, 1590, 1890}}, //35 + {161, 3034, 0, { 600, 1120, 1680, 1980}}, + {165, 3196, 0, { 630, 1204, 1770, 2100}}, + {169, 3362, 0, { 660, 1260, 1860, 2220}}, + {173, 3532, 0, { 720, 1316, 1950, 2310}}, + {177, 3706, 0, { 750, 1372, 2040, 2430}} //40 +}; + +int QRspec_getDataLength(int version, QRecLevel level) +{ + return qrspecCapacity[version].words - qrspecCapacity[version].ec[level]; +} + +int QRspec_getECCLength(int version, QRecLevel level) +{ + return qrspecCapacity[version].ec[level]; +} + +int QRspec_getMinimumVersion(int size, QRecLevel level) +{ + int i; + int words; + + for(i = 1; i <= QRSPEC_VERSION_MAX; i++) { + words = qrspecCapacity[i].words - qrspecCapacity[i].ec[level]; + if(words >= size) return i; + } + + return QRSPEC_VERSION_MAX; +} + +int QRspec_getWidth(int version) +{ + return qrspecCapacity[version].width; +} + +int QRspec_getRemainder(int version) +{ + return qrspecCapacity[version].remainder; +} + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +static const int lengthTableBits[4][3] = { + {10, 12, 14}, + { 9, 11, 13}, + { 8, 16, 16}, + { 8, 10, 12} +}; + +int QRspec_lengthIndicator(QRencodeMode mode, int version) +{ + int l; + + if(!QRinput_isSplittableMode(mode)) return 0; + if(version <= 9) { + l = 0; + } else if(version <= 26) { + l = 1; + } else { + l = 2; + } + + return lengthTableBits[mode][l]; +} + +int QRspec_maximumWords(QRencodeMode mode, int version) +{ + int l; + int bits; + int words; + + if(!QRinput_isSplittableMode(mode)) return 0; + if(version <= 9) { + l = 0; + } else if(version <= 26) { + l = 1; + } else { + l = 2; + } + + bits = lengthTableBits[mode][l]; + words = (1 << bits) - 1; + if(mode == QR_MODE_KANJI) { + words *= 2; // the number of bytes is required + } + + return words; +} + +/****************************************************************************** + * Error correction code + *****************************************************************************/ + +/** + * Table of the error correction code (Reed-Solomon block) + * See Table 12-16 (pp.30-36), JIS X0510:2004. + */ +static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = { + {{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}, + {{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, // 1 + {{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, + {{ 1, 0}, { 1, 0}, { 2, 0}, { 2, 0}}, + {{ 1, 0}, { 2, 0}, { 2, 0}, { 4, 0}}, + {{ 1, 0}, { 2, 0}, { 2, 2}, { 2, 2}}, // 5 + {{ 2, 0}, { 4, 0}, { 4, 0}, { 4, 0}}, + {{ 2, 0}, { 4, 0}, { 2, 4}, { 4, 1}}, + {{ 2, 0}, { 2, 2}, { 4, 2}, { 4, 2}}, + {{ 2, 0}, { 3, 2}, { 4, 4}, { 4, 4}}, + {{ 2, 2}, { 4, 1}, { 6, 2}, { 6, 2}}, //10 + {{ 4, 0}, { 1, 4}, { 4, 4}, { 3, 8}}, + {{ 2, 2}, { 6, 2}, { 4, 6}, { 7, 4}}, + {{ 4, 0}, { 8, 1}, { 8, 4}, {12, 4}}, + {{ 3, 1}, { 4, 5}, {11, 5}, {11, 5}}, + {{ 5, 1}, { 5, 5}, { 5, 7}, {11, 7}}, //15 + {{ 5, 1}, { 7, 3}, {15, 2}, { 3, 13}}, + {{ 1, 5}, {10, 1}, { 1, 15}, { 2, 17}}, + {{ 5, 1}, { 9, 4}, {17, 1}, { 2, 19}}, + {{ 3, 4}, { 3, 11}, {17, 4}, { 9, 16}}, + {{ 3, 5}, { 3, 13}, {15, 5}, {15, 10}}, //20 + {{ 4, 4}, {17, 0}, {17, 6}, {19, 6}}, + {{ 2, 7}, {17, 0}, { 7, 16}, {34, 0}}, + {{ 4, 5}, { 4, 14}, {11, 14}, {16, 14}}, + {{ 6, 4}, { 6, 14}, {11, 16}, {30, 2}}, + {{ 8, 4}, { 8, 13}, { 7, 22}, {22, 13}}, //25 + {{10, 2}, {19, 4}, {28, 6}, {33, 4}}, + {{ 8, 4}, {22, 3}, { 8, 26}, {12, 28}}, + {{ 3, 10}, { 3, 23}, { 4, 31}, {11, 31}}, + {{ 7, 7}, {21, 7}, { 1, 37}, {19, 26}}, + {{ 5, 10}, {19, 10}, {15, 25}, {23, 25}}, //30 + {{13, 3}, { 2, 29}, {42, 1}, {23, 28}}, + {{17, 0}, {10, 23}, {10, 35}, {19, 35}}, + {{17, 1}, {14, 21}, {29, 19}, {11, 46}}, + {{13, 6}, {14, 23}, {44, 7}, {59, 1}}, + {{12, 7}, {12, 26}, {39, 14}, {22, 41}}, //35 + {{ 6, 14}, { 6, 34}, {46, 10}, { 2, 64}}, + {{17, 4}, {29, 14}, {49, 10}, {24, 46}}, + {{ 4, 18}, {13, 32}, {48, 14}, {42, 32}}, + {{20, 4}, {40, 7}, {43, 22}, {10, 67}}, + {{19, 6}, {18, 31}, {34, 34}, {20, 61}},//40 +}; + +void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]) +{ + int b1, b2; + int data, ecc; + + b1 = eccTable[version][level][0]; + b2 = eccTable[version][level][1]; + data = QRspec_getDataLength(version, level); + ecc = QRspec_getECCLength(version, level); + + if(b2 == 0) { + spec[0] = b1; + spec[1] = data / b1; + spec[2] = ecc / b1; + spec[3] = spec[4] = 0; + } else { + spec[0] = b1; + spec[1] = data / (b1 + b2); + spec[2] = ecc / (b1 + b2); + spec[3] = b2; + spec[4] = spec[1] + 1; + } +} + +/****************************************************************************** + * Alignment pattern + *****************************************************************************/ + +/** + * Positions of alignment patterns. + * This array includes only the second and the third position of the alignment + * patterns. Rest of them can be calculated from the distance between them. + * + * See Table 1 in Appendix E (p.71) of JIS X0510:2004. + */ +static const int alignmentPattern[QRSPEC_VERSION_MAX+1][2] = { + { 0, 0}, + { 0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, // 1- 5 + {34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, // 6-10 + {30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, //11-15 + {26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, //16-20 + {28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, //21-25 + {30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, //26-30 + {30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, //31-35 + {24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, //35-40 +}; + +/** + * Put an alignment marker. + * @param frame destination frame data + * @param width frame width + * @param ox,oy center coordinate of the pattern + */ +static void QRspec_putAlignmentMarker(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa0, 0xa1, 0xa0, 0xa1, + 0xa1, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + }; + int x, y; + const unsigned char *s; + + frame += (oy - 2) * width + ox - 2; + s = finder; + for(y = 0; y < 5; y++) { + for(x = 0; x < 5; x++) { + frame[x] = s[x]; + } + frame += width; + s += 5; + } +} + +static void QRspec_putAlignmentPattern(int version, unsigned char *frame, int width) +{ + int d, w, x, y, cx, cy; + + if(version < 2) return; + + d = alignmentPattern[version][1] - alignmentPattern[version][0]; + if(d < 0) { + w = 2; + } else { + w = (width - alignmentPattern[version][0]) / d + 2; + } + + if(w * w - 3 == 1) { + x = alignmentPattern[version][0]; + y = alignmentPattern[version][0]; + QRspec_putAlignmentMarker(frame, width, x, y); + return; + } + + cx = alignmentPattern[version][0]; + for(x = 1; x < w - 1; x++) { + QRspec_putAlignmentMarker(frame, width, 6, cx); + QRspec_putAlignmentMarker(frame, width, cx, 6); + cx += d; + } + + cy = alignmentPattern[version][0]; + for(y = 0; y < w-1; y++) { + cx = alignmentPattern[version][0]; + for(x = 0; x < w-1; x++) { + QRspec_putAlignmentMarker(frame, width, cx, cy); + cx += d; + } + cy += d; + } +} + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Version information pattern (BCH coded). + * See Table 1 in Appendix D (p.68) of JIS X0510:2004. + */ +static const unsigned int versionPattern[QRSPEC_VERSION_MAX - 6] = { + 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, + 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, + 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, + 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, + 0x27541, 0x28c69 +}; + +unsigned int QRspec_getVersionPattern(int version) +{ + if(version < 7 || version > QRSPEC_VERSION_MAX) return 0; + + return versionPattern[version - 7]; +} + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/* See calcFormatInfo in tests/test_qrspec.c */ +static const unsigned int formatInfo[4][8] = { + {0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976}, + {0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0}, + {0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed}, + {0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b} +}; + +unsigned int QRspec_getFormatInfo(int mask, QRecLevel level) +{ + if(mask < 0 || mask > 7) return 0; + + return formatInfo[level][mask]; +} + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Put a finder pattern. + * @param frame destination frame data + * @param width frame width + * @param ox,oy upper-left coordinate of the pattern + */ +static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + }; + int x, y; + const unsigned char *s; + + frame += oy * width + ox; + s = finder; + for(y = 0; y < 7; y++) { + for(x = 0; x < 7; x++) { + frame[x] = s[x]; + } + frame += width; + s += 7; + } +} + + +static unsigned char *QRspec_createFrame(int version) +{ + unsigned char *frame, *p, *q; + int width; + int x, y; + unsigned int verinfo, v; + + width = qrspecCapacity[version].width; + frame = (unsigned char *)malloc((size_t)(width * width)); + if(frame == NULL) return NULL; + + memset(frame, 0, (size_t)(width * width)); + /* Finder pattern */ + putFinderPattern(frame, width, 0, 0); + putFinderPattern(frame, width, width - 7, 0); + putFinderPattern(frame, width, 0, width - 7); + /* Separator */ + p = frame; + q = frame + width * (width - 7); + for(y = 0; y < 7; y++) { + p[7] = 0xc0; + p[width - 8] = 0xc0; + q[7] = 0xc0; + p += width; + q += width; + } + memset(frame + width * 7, 0xc0, 8); + memset(frame + width * 8 - 8, 0xc0, 8); + memset(frame + width * (width - 8), 0xc0, 8); + /* Mask format information area */ + memset(frame + width * 8, 0x84, 9); + memset(frame + width * 9 - 8, 0x84, 8); + p = frame + 8; + for(y = 0; y < 8; y++) { + *p = 0x84; + p += width; + } + p = frame + width * (width - 7) + 8; + for(y = 0; y < 7; y++) { + *p = 0x84; + p += width; + } + /* Timing pattern */ + p = frame + width * 6 + 8; + q = frame + width * 8 + 6; + for(x = 1; x < width-15; x++) { + *p = 0x90 | (x & 1); + *q = 0x90 | (x & 1); + p++; + q += width; + } + /* Alignment pattern */ + QRspec_putAlignmentPattern(version, frame, width); + + /* Version information */ + if(version >= 7) { + verinfo = QRspec_getVersionPattern(version); + + p = frame + width * (width - 11); + v = verinfo; + for(x = 0; x < 6; x++) { + for(y = 0; y < 3; y++) { + p[width * y + x] = 0x88 | (v & 1); + v = v >> 1; + } + } + + p = frame + width - 11; + v = verinfo; + for(y = 0; y < 6; y++) { + for(x = 0; x < 3; x++) { + p[x] = 0x88 | (v & 1); + v = v >> 1; + } + p += width; + } + } + /* and a little bit... */ + frame[width * (width - 8) + 8] = 0x81; + + return frame; +} + +unsigned char *QRspec_newFrame(int version) +{ + if(version < 1 || version > QRSPEC_VERSION_MAX) return NULL; + + return QRspec_createFrame(version); +} diff --git a/genqrcode/qrspec.h b/genqrcode/qrspec.h new file mode 100644 index 0000000000..017bb5518a --- /dev/null +++ b/genqrcode/qrspec.h @@ -0,0 +1,174 @@ +/* + * qrencode - QR Code encoder + * + * QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QRSPEC_H +#define QRSPEC_H + +#include "qrencode.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +/** + * Maximum width of a symbol + */ +#define QRSPEC_WIDTH_MAX 177 + +/** + * Return maximum data code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return maximum size (bytes) + */ +extern int QRspec_getDataLength(int version, QRecLevel level); + +/** + * Return maximum error correction code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return ECC size (bytes) + */ +extern int QRspec_getECCLength(int version, QRecLevel level); + +/** + * Return a version number that satisfies the input code length. + * @param size input code length (byte) + * @param level error correction level + * @return version number + */ +extern int QRspec_getMinimumVersion(int size, QRecLevel level); + +/** + * Return the width of the symbol for the version. + * @param version vesion of the symbol + * @return width of the symbol + */ +extern int QRspec_getWidth(int version); + +/** + * Return the numer of remainder bits. + * @param version vesion of the symbol + * @return number of remainder bits + */ +extern int QRspec_getRemainder(int version); + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * Return the size of length indicator for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the size of the appropriate length indicator (bits). + */ +extern int QRspec_lengthIndicator(QRencodeMode mode, int version); + +/** + * Return the maximum length for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the maximum length (bytes) + */ +extern int QRspec_maximumWords(QRencodeMode mode, int version); + +/****************************************************************************** + * Error correction code + *****************************************************************************/ + +/** + * Return an array of ECC specification. + * @param version version of the symbol + * @param level error correction level + * @param spec an array of ECC specification contains as following: + * {# of type1 blocks, # of data code, # of ecc code, + * # of type2 blocks, # of data code} + */ +void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]); + +#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3]) +#define QRspec_rsBlockNum1(__spec__) (__spec__[0]) +#define QRspec_rsDataCodes1(__spec__) (__spec__[1]) +#define QRspec_rsEccCodes1(__spec__) (__spec__[2]) +#define QRspec_rsBlockNum2(__spec__) (__spec__[3]) +#define QRspec_rsDataCodes2(__spec__) (__spec__[4]) +#define QRspec_rsEccCodes2(__spec__) (__spec__[2]) + +#define QRspec_rsDataLength(__spec__) \ + ((QRspec_rsBlockNum1(__spec__) * QRspec_rsDataCodes1(__spec__)) + \ + (QRspec_rsBlockNum2(__spec__) * QRspec_rsDataCodes2(__spec__))) +#define QRspec_rsEccLength(__spec__) \ + (QRspec_rsBlockNum(__spec__) * QRspec_rsEccCodes1(__spec__)) + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Return BCH encoded version information pattern that is used for the symbol + * of version 7 or greater. Use lower 18 bits. + * @param version version of the symbol + * @return BCH encoded version information pattern + */ +extern unsigned int QRspec_getVersionPattern(int version); + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/** + * Return BCH encoded format information pattern. + * @param mask mask number + * @param level error correction level + * @return BCH encoded format information pattern + */ +extern unsigned int QRspec_getFormatInfo(int mask, QRecLevel level); + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Return a copy of initialized frame. + * @param version version of the symbol + * @return Array of unsigned char. You can free it by free(). + */ +extern unsigned char *QRspec_newFrame(int version); + +/****************************************************************************** + * Mode indicator + *****************************************************************************/ + +/** + * Mode indicator. See Table 2 of JIS X0510:2004, p.16. + */ +#define QRSPEC_MODEID_ECI 7 +#define QRSPEC_MODEID_NUM 1 +#define QRSPEC_MODEID_AN 2 +#define QRSPEC_MODEID_8 4 +#define QRSPEC_MODEID_KANJI 8 +#define QRSPEC_MODEID_FNC1FIRST 5 +#define QRSPEC_MODEID_FNC1SECOND 9 +#define QRSPEC_MODEID_STRUCTURE 3 +#define QRSPEC_MODEID_TERMINATOR 0 + +#endif /* QRSPEC_H */ diff --git a/genqrcode/rsecc.c b/genqrcode/rsecc.c new file mode 100644 index 0000000000..95be0f00c5 --- /dev/null +++ b/genqrcode/rsecc.c @@ -0,0 +1,149 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon error correction code encoder specialized for QR code. + * This code is rewritten by Kentaro Fukuchi, referring to the FEC library + * developed by Phil Karn (KA9Q). + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * Copyright (C) 2014-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <string.h> +#if HAVE_LIBPTHREAD +#include <pthread.h> +#endif + +#include "rsecc.h" + +#if HAVE_LIBPTHREAD +static pthread_mutex_t RSECC_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static int initialized = 0; + +#define SYMBOL_SIZE (8) +#define symbols ((1U << SYMBOL_SIZE) - 1) +static const unsigned int proot = 0x11d; /* stands for x^8+x^4+x^3+x^2+1 (see p.37 of JIS X0510:2004) */ + +/* min/max codeword length of ECC, calculated from the specification. */ +#define min_length (2) +#define max_length (30) +#define max_generatorSize (max_length) + +static unsigned char alpha[symbols + 1]; +static unsigned char aindex[symbols + 1]; +static unsigned char generator[max_length - min_length + 1][max_generatorSize + 1]; +static unsigned char generatorInitialized[max_length - min_length + 1]; + +static void RSECC_initLookupTable(void) +{ + unsigned int i, b; + + alpha[symbols] = 0; + aindex[0] = symbols; + + b = 1; + for(i = 0; i < symbols; i++) { + alpha[i] = (unsigned char)b; + aindex[b] = (unsigned char)i; + b <<= 1; + if(b & (symbols + 1)) { + b ^= proot; + } + b &= symbols; + } +} + +static void RSECC_init(void) +{ + RSECC_initLookupTable(); + memset(generatorInitialized, 0, (max_length - min_length + 1)); + initialized = 1; +} + +static void generator_init(size_t length) +{ + size_t i, j; + int g[max_generatorSize + 1]; + + g[0] = 1; + for(i = 0; i < length; i++) { + g[i + 1] = 1; + /* Because g[0] never be zero, skipped some conditional checks. */ + for(j = i; j > 0; j--) { + g[j] = g[j - 1] ^ alpha[(aindex[g[j]] + i) % symbols]; + } + g[0] = alpha[(aindex[g[0]] + i) % symbols]; + } + + for(i = 0; i <= length; i++) { + generator[length - min_length][i] = aindex[g[i]]; + } + + generatorInitialized[length - min_length] = 1; +} + +int RSECC_encode(size_t data_length, size_t ecc_length, const unsigned char *data, unsigned char *ecc) +{ + size_t i, j; + unsigned char feedback; + unsigned char *gen; + +#if HAVE_LIBPTHREAD + pthread_mutex_lock(&RSECC_mutex); +#endif + if(!initialized) { + RSECC_init(); + } +#if HAVE_LIBPTHREAD + pthread_mutex_unlock(&RSECC_mutex); +#endif + + if(ecc_length > max_length) return -1; + + memset(ecc, 0, ecc_length); +#if HAVE_LIBPTHREAD + pthread_mutex_lock(&RSECC_mutex); +#endif + if(!generatorInitialized[ecc_length - min_length]) generator_init(ecc_length); +#if HAVE_LIBPTHREAD + pthread_mutex_unlock(&RSECC_mutex); +#endif + gen = generator[ecc_length - min_length]; + + for(i = 0; i < data_length; i++) { + feedback = aindex[data[i] ^ ecc[0]]; + if(feedback != symbols) { + for(j = 1; j < ecc_length; j++) { + ecc[j] ^= alpha[(unsigned int)(feedback + gen[ecc_length - j]) % symbols]; + } + } + memmove(&ecc[0], &ecc[1], ecc_length - 1); + if(feedback != symbols) { + ecc[ecc_length - 1] = alpha[(unsigned int)(feedback + gen[0]) % symbols]; + } else { + ecc[ecc_length - 1] = 0; + } + } + + return 0; +} diff --git a/genqrcode/rsecc.h b/genqrcode/rsecc.h new file mode 100644 index 0000000000..2c17dedb92 --- /dev/null +++ b/genqrcode/rsecc.h @@ -0,0 +1,31 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon error correction code encoder specialized for QR code. + * This code is rewritten by Kentaro Fukuchi, referring to the FEC library + * developed by Phil Karn (KA9Q). + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * Copyright (C) 2014-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef RSECC_H +#define RSECC_H + +extern int RSECC_encode(size_t data_length, size_t ecc_length, const unsigned char *data, unsigned char *ecc); + +#endif /* RSECC_H */ diff --git a/genqrcode/split.c b/genqrcode/split.c new file mode 100644 index 0000000000..9975128a5e --- /dev/null +++ b/genqrcode/split.c @@ -0,0 +1,323 @@ +/* + * qrencode - QR Code encoder + * + * Input data splitter. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "qrencode.h" +#include "qrinput.h" +#include "qrspec.h" +#include "split.h" + +#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10) +#define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0) + +#if !HAVE_STRDUP +#undef strdup +char *strdup(const char *s) +{ + size_t len = strlen(s) + 1; + void *newstring = malloc(len); + if(newstring == NULL) return NULL; + return (char *)memcpy(newstring, s, len); +} +#endif + +static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint) +{ + unsigned char c, d; + unsigned int word; + + c = (unsigned char)string[0]; + + if(c == '\0') return QR_MODE_NUL; + if(isdigit(c)) { + return QR_MODE_NUM; + } else if(isalnum(c)) { + return QR_MODE_AN; + } else if(hint == QR_MODE_KANJI) { + d = (unsigned char)string[1]; + if(d != '\0') { + word = ((unsigned int)c << 8) | d; + if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) { + return QR_MODE_KANJI; + } + } + } + + return QR_MODE_8; +} + +static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint); +static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint); + +static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint) +{ + const char *p; + int ret; + int run; + int dif; + int ln; + QRencodeMode mode; + + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string; + while(isdigit(*p)) { + p++; + } + run = (int)(p - string); + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_8) { + dif = QRinput_estimateBitsModeNum(run) + 4 + ln + + QRinput_estimateBitsMode8(1) /* + 4 + l8 */ + - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */; + if(dif > 0) { + return Split_eat8(string, input, hint); + } + } + if(mode == QR_MODE_AN) { + dif = QRinput_estimateBitsModeNum(run) + 4 + ln + + QRinput_estimateBitsModeAn(1) /* + 4 + la */ + - QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */; + if(dif > 0) { + return Split_eatAn(string, input, hint); + } + } + + ret = QRinput_append(input, QR_MODE_NUM, run, (const unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p, *q; + int ret; + int run; + int dif; + int la, ln; + + la = QRspec_lengthIndicator(QR_MODE_AN, input->version); + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string; + while(isalnum(*p)) { + if(isdigit(*p)) { + q = p; + while(isdigit(*q)) { + q++; + } + dif = QRinput_estimateBitsModeAn((int)(p - string)) /* + 4 + la */ + + QRinput_estimateBitsModeNum((int)(q - p)) + 4 + ln + + (isalnum(*q)?(4 + ln):0) + - QRinput_estimateBitsModeAn((int)(q - string)) /* - 4 - la */; + if(dif < 0) { + break; + } + p = q; + } else { + p++; + } + } + + run = (int)(p - string); + + if(*p && !isalnum(*p)) { + dif = QRinput_estimateBitsModeAn(run) + 4 + la + + QRinput_estimateBitsMode8(1) /* + 4 + l8 */ + - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */; + if(dif > 0) { + return Split_eat8(string, input, hint); + } + } + + ret = QRinput_append(input, QR_MODE_AN, run, (const unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p; + int ret; + int run; + + p = string; + while(Split_identifyMode(p, hint) == QR_MODE_KANJI) { + p += 2; + } + run = (int)(p - string); + ret = QRinput_append(input, QR_MODE_KANJI, run, (const unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p, *q; + QRencodeMode mode; + int ret; + int run; + int dif; + int la, ln, l8; + int swcost; + + la = QRspec_lengthIndicator(QR_MODE_AN, input->version); + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + l8 = QRspec_lengthIndicator(QR_MODE_8, input->version); + + p = string + 1; + while(*p != '\0') { + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_KANJI) { + break; + } + if(mode == QR_MODE_NUM) { + q = p; + while(isdigit(*q)) { + q++; + } + if(Split_identifyMode(q, hint) == QR_MODE_8) { + swcost = 4 + l8; + } else { + swcost = 0; + } + dif = QRinput_estimateBitsMode8((int)(p - string)) /* + 4 + l8 */ + + QRinput_estimateBitsModeNum((int)(q - p)) + 4 + ln + + swcost + - QRinput_estimateBitsMode8((int)(q - string)) /* - 4 - l8 */; + if(dif < 0) { + break; + } + p = q; + } else if(mode == QR_MODE_AN) { + q = p; + while(isalnum(*q)) { + q++; + } + if(Split_identifyMode(q, hint) == QR_MODE_8) { + swcost = 4 + l8; + } else { + swcost = 0; + } + dif = QRinput_estimateBitsMode8((int)(p - string)) /* + 4 + l8 */ + + QRinput_estimateBitsModeAn((int)(q - p)) + 4 + la + + swcost + - QRinput_estimateBitsMode8((int)(q - string)) /* - 4 - l8 */; + if(dif < 0) { + break; + } + p = q; + } else { + p++; + } + } + + run = (int)(p - string); + ret = QRinput_append(input, QR_MODE_8, run, (const unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_splitString(const char *string, QRinput *input, + QRencodeMode hint) +{ + int length; + QRencodeMode mode; + + while(*string != '\0') { + mode = Split_identifyMode(string, hint); + if(mode == QR_MODE_NUM) { + length = Split_eatNum(string, input, hint); + } else if(mode == QR_MODE_AN) { + length = Split_eatAn(string, input, hint); + } else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) { + length = Split_eatKanji(string, input, hint); + } else { + length = Split_eat8(string, input, hint); + } + if(length == 0) break; + if(length < 0) return -1; + string += length; + } + + return 0; +} + +static char *dupAndToUpper(const char *str, QRencodeMode hint) +{ + char *newstr, *p; + QRencodeMode mode; + + newstr = strdup(str); + if(newstr == NULL) return NULL; + + p = newstr; + while(*p != '\0') { + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_KANJI) { + p += 2; + } else { + if (*p >= 'a' && *p <= 'z') { + *p = (char)((int)*p - 32); + } + p++; + } + } + + return newstr; +} + +int Split_splitStringToQRinput(const char *string, QRinput *input, + QRencodeMode hint, int casesensitive) +{ + char *newstr; + int ret; + + if(string == NULL || *string == '\0') { + errno = EINVAL; + return -1; + } + if(!casesensitive) { + newstr = dupAndToUpper(string, hint); + if(newstr == NULL) return -1; + ret = Split_splitString(newstr, input, hint); + free(newstr); + } else { + ret = Split_splitString(string, input, hint); + } + + return ret; +} diff --git a/genqrcode/split.h b/genqrcode/split.h new file mode 100644 index 0000000000..81829e078e --- /dev/null +++ b/genqrcode/split.h @@ -0,0 +1,47 @@ +/* + * qrencode - QR Code encoder + * + * Input data splitter. + * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SPLIT_H +#define SPLIT_H + +#include "qrencode.h" + +/** + * Split the input string (null terminated) into QRinput. + * @param string input string + * @param hint give QR_MODE_KANJI if the input string contains Kanji character encoded in Shift-JIS. If not, give QR_MODE_8. + * @param casesensitive 0 for case-insensitive encoding (all alphabet characters are replaced to UPPER-CASE CHARACTERS. + * @retval 0 success. + * @retval -1 an error occurred. errno is set to indicate the error. See + * Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern int Split_splitStringToQRinput(const char *string, QRinput *input, + QRencodeMode hint, int casesensitive); + +#endif /* SPLIT_H */ diff --git a/genqrcode/tests/CMakeLists.txt b/genqrcode/tests/CMakeLists.txt new file mode 100644 index 0000000000..4c4a5e8171 --- /dev/null +++ b/genqrcode/tests/CMakeLists.txt @@ -0,0 +1,81 @@ +add_library(common + common.c common.h) +target_link_libraries(common qrencode) + +add_library(rscode + rscode.c rscode.h) +target_link_libraries(rscode common) + +macro(MAKE_TEST test_name) + set(ADDITIONAL_LIBS "${ARGN}") + add_executable(${test_name} ${test_name}.c) + target_link_libraries(${test_name} common ${ADDITIONAL_LIBS}) + add_test(${test_name} ${test_name}) +endmacro(MAKE_TEST) + +if(TARGET PNG::PNG) + add_executable(create_frame_pattern create_frame_pattern.c) + target_link_libraries(create_frame_pattern common PNG::PNG) + + add_executable(create_mqr_frame_pattern create_mqr_frame_pattern.c) + target_link_libraries(create_mqr_frame_pattern common PNG::PNG) +endif() + +if(HAVE_SDL) + add_executable(view_qrcode view_qrcode.c) + target_link_libraries(view_qrcode common) +endif(HAVE_SDL) + +if(TARGET Threads::Threads) + if(HAVE_SYS_TIME_H) + add_definitions(-DHAVE_SYS_TIME_H) + endif() + + if(HAVE_TIME_H) + add_definitions(-DHAVE_TIME_H) + endif() + + add_executable(prof_qrencode prof_qrencode.c) + target_link_libraries(prof_qrencode common Threads::Threads) + + if(HAVE_PTHREAD_H) + add_executable(pthread_qrencode pthread_qrencode.c) + target_link_libraries(pthread_qrencode common Threads::Threads) + endif() +endif() + +MAKE_TEST(test_bitstream) +MAKE_TEST(test_estimatebit) +MAKE_TEST(test_split) + +if(TARGET ICONV::ICONV) + add_library(decoder STATIC + decoder.c decoder.h + datachunk.c datachunk.h + rsecc_decoder.c rsecc_decoder.h) + target_link_libraries(decoder ICONV::ICONV) + + MAKE_TEST(test_qrinput decoder) + MAKE_TEST(test_qrspec decoder) + target_compile_definitions(test_qrspec PRIVATE -DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/") + MAKE_TEST(test_mqrspec decoder) + MAKE_TEST(test_qrencode decoder) + MAKE_TEST(test_split_urls decoder) + MAKE_TEST(test_monkey decoder) + + include(CheckCSourceCompiles) + check_c_source_compiles( + "int main(){ + const int w = 1; + char buf[w]; + return 0; + }" + FIXED_SIZE_BUFFER_INITIALIZATION) + + if(FIXED_SIZE_BUFFER_INITIALIZATION) + MAKE_TEST(test_mask decoder) + MAKE_TEST(test_mmask decoder) + MAKE_TEST(test_rs rscode decoder) + endif() +endif() + diff --git a/genqrcode/tests/Makefile.am b/genqrcode/tests/Makefile.am new file mode 100644 index 0000000000..c7cfad1b37 --- /dev/null +++ b/genqrcode/tests/Makefile.am @@ -0,0 +1,86 @@ +AM_CFLAGS = +AM_LDFLAGS = + +if HAVE_SDL +sdlPROGRAMS = view_qrcode +AM_CFLAGS += $(SDL_CFLAGS) +AM_LDFLAGS += $(SDL_LIBS) +endif + +if HAVE_PNG +pngPROGRAMS = create_frame_pattern create_mqr_frame_pattern +endif + +check_PROGRAMS = test_qrinput test_bitstream test_estimatebit test_qrspec \ + test_rs test_qrencode test_mqrspec test_split test_mask \ + test_mmask test_split_urls test_monkey +noinst_PROGRAMS = $(pngPROGRAMS) $(sdlPROGRAMS) $(check_PROGRAMS) prof_qrencode +noinst_LIBRARIES = libdecoder.a +DECODER_LIBS = libdecoder.a $(LIBICONV) +noinst_HEADERS = common.h rscode.h +if HAVE_LIBPTHREAD +noinst_PROGRAMS += pthread_qrencode +endif + +TESTS = $(check_PROGRAMS) +EXTRA_DIST = test_all.sh test_basic.sh test_configure.sh frame URI_testset.inc CMakeLists.txt + +libdecoder_a_SOURCES = decoder.c decoder.h datachunk.c datachunk.h rsecc_decoder.c rsecc_decoder.h + +test_qrinput_SOURCES = test_qrinput.c common.c +test_qrinput_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_bitstream_SOURCES = test_bitstream.c common.c +test_bitstream_LDADD = ../libqrencode.la + +test_estimatebit_SOURCES = test_estimatebit.c common.c +test_estimatebit_LDADD = ../libqrencode.la + +test_qrspec_SOURCES = test_qrspec.c common.c +test_qrspec_CPPFLAGS = -DSRCDIR=\"$(srcdir)/\" +test_qrspec_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_mqrspec_SOURCES = test_mqrspec.c common.c +test_mqrspec_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_rs_SOURCES = test_rs.c rscode.c common.c +test_rs_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_qrencode_SOURCES = test_qrencode.c common.c +test_qrencode_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_split_SOURCES = test_split.c common.c +test_split_LDADD = ../libqrencode.la + +test_split_urls_SOURCES = test_split_urls.c common.c +test_split_urls_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_monkey_SOURCES = test_monkey.c common.c +test_monkey_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_mask_SOURCES = test_mask.c common.c +test_mask_LDADD = $(DECODER_LIBS) ../libqrencode.la + +test_mmask_SOURCES = test_mmask.c common.c +test_mmask_LDADD = $(DECODER_LIBS) ../libqrencode.la + +prof_qrencode_SOURCES = prof_qrencode.c common.c +prof_qrencode_LDADD = ../libqrencode.la + +pthread_qrencode_SOURCES = pthread_qrencode.c common.c +pthread_qrencode_LDADD = ../libqrencode.la + +if HAVE_PNG +create_frame_pattern_SOURCES = create_frame_pattern.c common.c +create_frame_pattern_CFLAGS = $(png_CFLAGS) $(AM_CFLAGS) +create_frame_pattern_LDADD = ../libqrencode.la $(png_LIBS) + +create_mqr_frame_pattern_SOURCES = create_mqr_frame_pattern.c common.c +create_mqr_frame_pattern_CFLAGS = $(png_CFLAGS) $(AM_CFLAGS) +create_mqr_frame_pattern_LDADD = ../libqrencode.la $(png_LIBS) +endif + +if HAVE_SDL +view_qrcode_SOURCES = view_qrcode.c common.c +view_qrcode_LDADD = ../libqrencode.la +endif diff --git a/genqrcode/tests/URI_testset.inc b/genqrcode/tests/URI_testset.inc new file mode 100644 index 0000000000..9d0fa35ea0 --- /dev/null +++ b/genqrcode/tests/URI_testset.inc @@ -0,0 +1,1273 @@ +struct TestSet { + size_t expected_length; + char *url; +}; + +static struct TestSet testset[] = { +{3132,"http://ads.bluelithium.com/clk?3,eJytjcFqwzAQRL8mNyO0luUoiB7WcQUGS8RFbXBuqVEcxxbKwSDy93HS0P5AH3uYYXd2AKT4hpOjJ-d4njGWdxIySB2nnB0hoVJKRvkmhTXb8GRyIWBVdw0W01bRAh-Y3Vfb4ItS4Ee.fcqdQBJLQsTg2.5nmzOT479QirH4fOkKcfnfL9WDMk09vhd.ZxpM2cSD17G2yh8uetZWTfoGQ7tXY22N1xa53lfc2DYz.W.yLUnO83xdMVylapkYI7kdzyGQLvjF3wHZQ1eK,http%3A%2F%2Fomicronpath.com%2F%3Fa%3D448%26c%3D3201%26s1%3DYahooStream_917_Nevada4"}, +{3745,"http://ads.bluelithium.com/clk?3,eJytjd2OgjAQhZ.GO9K0lEpJ48WwUNekdIWoBO8UCfKX7gUJ4tNv3bj6AvtlLs7knDlDiDgzSi8sqDzOAtfnviAecSuGGT25DhZCUGwN4tOAOX1lDGxUmULYZT0O4cGnyYoankQcsvrjV245oClCiDfDn8.UYQn.QsS7cP.UGwDbX9vXjdSp6uLwHUuIjtL5ay1btZPDsU3GZCf7ZCZNkcte5YdG3.c33cZY5wU7pq.LleNcx.F7QWHhSjvTNKH5dDUGlWaw-w-Jy1ek,http%3A%2F%2Ftanphysics.com%2Farticles%2Freview1.php%3Futm_source%3DUSA%26utm_medium%3DYHO%26utm_content%3D917-STRM4%26utm_campaign%3DYHO%26keyword%3DYHO-917-STRM4"}, +{896,"http://amigo.geneontology.org/cgi-bin/amigo/go.cgi?view=details&search_constraint=terms&depth=0&query=GO:0042438"}, +{611,"http://amigo.geneontology.org/cgi-bin/amigo/gp-assoc.cgi?gp=UniProtKB:P30046"}, +{212,"http://answers.yahoo.com/"}, +{196,"http://autos.yahoo.com/"}, +{348,"http://baseball.fantasysports.yahoo.com/b1"}, +{234,"http://biogps.org/gene/1652/"}, +{644,"http://blog.washingtonpost.com/dcsportsbog/2007/05/a_caron_butler_surprise.html"}, +{340,"http://ca.wikipedia.org/wiki/Caron_Butler"}, +{212,"http://careers.yahoo.com/"}, +{404,"http://commons.wikimedia.org/wiki/Atlas_of_Turkey"}, +{380,"http://creativecommons.org/licenses/by-sa/3.0/"}, +{380,"http://da.wikipedia.org/wiki/Johann_David_Wyss"}, +{244,"http://de.wikipedia.org/wiki/"}, +{340,"http://de.wikipedia.org/wiki/Caron_Butler"}, +{380,"http://de.wikipedia.org/wiki/Johann_David_Wyss"}, +{340,"http://de.wikipedia.org/wiki/Massey_Lopes"}, +{512,"http://de.wikipedia.org/wiki/T%C3%BCrkische_Verfassung_von_1921"}, +{336,"http://dx.doi.org/10.1002%2Felps.11501301201"}, +{334,"http://dx.doi.org/10.1006%2Fbbrc.1993.2524"}, +{296,"http://dx.doi.org/10.1007%2Fs003359900858"}, +{304,"http://dx.doi.org/10.1021%2Fbi982184o"}, +{402,"http://dx.doi.org/10.1034%2Fj.1600-0625.2003.120307.x"}, +{255,"http://dx.doi.org/10.1038%2F990031"}, +{296,"http://dx.doi.org/10.1038%2Fmsb4100134"}, +{282,"http://dx.doi.org/10.1038%2Fnbt810"}, +{329,"http://dx.doi.org/10.1073%2Fpnas.242603899"}, +{326,"http://dx.doi.org/10.1074%2Fjbc.M203220200"}, +{307,"http://dx.doi.org/10.1101%2Fgr.2596504"}, +{360,"http://dx.doi.org/10.1186%2Fgb-2004-5-10-r84"}, +{228,"http://education.yahoo.com/"}, +{364,"http://en.m.wikipedia.org/wiki/Ambrose_Dyson"}, +{356,"http://en.m.wikipedia.org/wiki/Caron_Butler"}, +{340,"http://en.m.wikipedia.org/wiki/DDT_(gene)"}, +{396,"http://en.m.wikipedia.org/wiki/Johann_David_Wyss"}, +{332,"http://en.m.wikipedia.org/wiki/Lady_Anne"}, +{492,"http://en.m.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet"}, +{308,"http://en.m.wikipedia.org/wiki/Tumula"}, +{480,"http://en.m.wikipedia.org/wiki/Turkish_Constitution_of_1921"}, +{556,"http://en.m.wikipedia.org/wiki/Vietnam_University_Admission_Rankings"}, +{444,"http://en.m.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{196,"http://en.wikipedia.org"}, +{816,"http://en.wikipedia.org/w/index.php?title=2013%E2%80%9314_Milwaukee_Bucks_season&action=edit&redlink=1"}, +{548,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&action=edit"}, +{628,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&action=edit§ion=1"}, +{572,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&action=history"}, +{548,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&action=info"}, +{552,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&oldid=562636681"}, +{564,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&printable=yes"}, +{564,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&veaction=edit"}, +{644,"http://en.wikipedia.org/w/index.php?title=Ambrose_Dyson&veaction=edit§ion=1"}, +{540,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&action=edit"}, +{620,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&action=edit§ion=1"}, +{564,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&action=history"}, +{540,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&action=info"}, +{544,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&oldid=571697645"}, +{556,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&printable=yes"}, +{556,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&veaction=edit"}, +{636,"http://en.wikipedia.org/w/index.php?title=Caron_Butler&veaction=edit§ion=1"}, +{780,"http://en.wikipedia.org/w/index.php?title=Court_of_Jurisdictional_Conflict&action=edit&redlink=1"}, +{524,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&action=edit"}, +{604,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&action=edit§ion=1"}, +{548,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&action=history"}, +{524,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&action=info"}, +{528,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&oldid=453962249"}, +{540,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&printable=yes"}, +{540,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&veaction=edit"}, +{620,"http://en.wikipedia.org/w/index.php?title=DDT_(gene)&veaction=edit§ion=1"}, +{724,"http://en.wikipedia.org/w/index.php?title=Devonshire_County_Council&action=edit&redlink=1"}, +{812,"http://en.wikipedia.org/w/index.php?title=H%C3%A0_T%C4%A9nh_Gifted_High_School&action=edit&redlink=1"}, +{820,"http://en.wikipedia.org/w/index.php?title=H%C6%B0ng_Y%C3%AAn_Gifted_High_School&action=edit&redlink=1"}, +{580,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&action=edit"}, +{660,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&action=edit§ion=1"}, +{660,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&action=edit§ion=2"}, +{604,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&action=history"}, +{580,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&action=info"}, +{584,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&oldid=568638498"}, +{596,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&printable=yes"}, +{596,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&veaction=edit"}, +{676,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&veaction=edit§ion=1"}, +{676,"http://en.wikipedia.org/w/index.php?title=Johann_David_Wyss&veaction=edit§ion=2"}, +{684,"http://en.wikipedia.org/w/index.php?title=Johann_Emmanuel_Wyss&action=edit&redlink=1"}, +{652,"http://en.wikipedia.org/w/index.php?title=Josh_Oppenheimer&action=edit&redlink=1"}, +{588,"http://en.wikipedia.org/w/index.php?title=Lady_Ann&action=edit&redlink=1"}, +{516,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&action=edit"}, +{596,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&action=edit§ion=1"}, +{540,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&action=history"}, +{516,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&action=info"}, +{520,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&oldid=372343156"}, +{532,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&printable=yes"}, +{532,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&veaction=edit"}, +{612,"http://en.wikipedia.org/w/index.php?title=Lady_Anne&veaction=edit§ion=1"}, +{740,"http://en.wikipedia.org/w/index.php?title=Military_Court_of_Cassation&action=edit&redlink=1"}, +{820,"http://en.wikipedia.org/w/index.php?title=Military_High_Court_of_Administration&action=edit&redlink=1"}, +{620,"http://en.wikipedia.org/w/index.php?title=Monte_Mathis&action=edit&redlink=1"}, +{764,"http://en.wikipedia.org/w/index.php?title=Quang_Trung_Gifted_High_School&action=edit&redlink=1"}, +{740,"http://en.wikipedia.org/w/index.php?title=Robert_Hackett_(basketball)&action=edit&redlink=1"}, +{676,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&action=edit"}, +{756,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&action=edit§ion=1"}, +{700,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&action=history"}, +{676,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&action=info"}, +{680,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&oldid=545042390"}, +{692,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&printable=yes"}, +{692,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&veaction=edit"}, +{772,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&veaction=edit§ion=1"}, +{772,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&veaction=edit§ion=2"}, +{772,"http://en.wikipedia.org/w/index.php?title=Sir_Massey_Lopes,_3rd_Baronet&veaction=edit§ion=3"}, +{788,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Ambrose+Dyson"}, +{780,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Caron+Butler"}, +{796,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=DDT+%28gene%29"}, +{820,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Johann+David+Wyss"}, +{756,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Lady+Anne"}, +{932,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Sir+Massey+Lopes%2C+3rd+Baronet"}, +{732,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Tumula"}, +{908,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Turkish+Constitution+of+1921"}, +{980,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Vietnam+University+Admission+Rankings"}, +{868,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=book_creator&referer=Vy%C5%A1n%C3%BD+Slavkov"}, +{1004,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Ambrose+Dyson&oldid=562636681&writer=rl"}, +{996,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Caron+Butler&oldid=571697645&writer=rl"}, +{1012,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=DDT+%28gene%29&oldid=453962249&writer=rl"}, +{1036,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Johann+David+Wyss&oldid=568638498&writer=rl"}, +{972,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Lady+Anne&oldid=372343156&writer=rl"}, +{1148,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Sir+Massey+Lopes%2C+3rd+Baronet&oldid=545042390&writer=rl"}, +{948,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Tumula&oldid=401070860&writer=rl"}, +{1124,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Turkish+Constitution+of+1921&oldid=566504847&writer=rl"}, +{1196,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Vietnam+University+Admission+Rankings&oldid=568532236&writer=rl"}, +{1084,"http://en.wikipedia.org/w/index.php?title=Special:Book&bookcmd=render_article&arttitle=Vy%C5%A1n%C3%BD+Slavkov&oldid=541325469&writer=rl"}, +{672,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Ambrose_Dyson&id=562636681"}, +{664,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Caron_Butler&id=571697645"}, +{680,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=DDT_%28gene%29&id=453962249"}, +{704,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Johann_David_Wyss&id=568638498"}, +{640,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Lady_Anne&id=372343156"}, +{816,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Sir_Massey_Lopes%2C_3rd_Baronet&id=545042390"}, +{616,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Tumula&id=401070860"}, +{792,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Turkish_Constitution_of_1921&id=566504847"}, +{864,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Vietnam_University_Admission_Rankings&id=568532236"}, +{752,"http://en.wikipedia.org/w/index.php?title=Special:Cite&page=Vy%C5%A1n%C3%BD_Slavkov&id=541325469"}, +{668,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Ambrose+Dyson"}, +{764,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Ambrose+Dyson&type=signup"}, +{660,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Caron+Butler"}, +{756,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Caron+Butler&type=signup"}, +{676,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=DDT+%28gene%29"}, +{772,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=DDT+%28gene%29&type=signup"}, +{700,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Johann+David+Wyss"}, +{796,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Johann+David+Wyss&type=signup"}, +{636,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Lady+Anne"}, +{732,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Lady+Anne&type=signup"}, +{812,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Sir+Massey+Lopes%2C+3rd+Baronet"}, +{908,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Sir+Massey+Lopes%2C+3rd+Baronet&type=signup"}, +{612,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Tumula"}, +{708,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Tumula&type=signup"}, +{788,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Turkish+Constitution+of+1921"}, +{884,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Turkish+Constitution+of+1921&type=signup"}, +{860,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Vietnam+University+Admission+Rankings"}, +{956,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Vietnam+University+Admission+Rankings&type=signup"}, +{748,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Vy%C5%A1n%C3%BD+Slavkov"}, +{844,"http://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Vy%C5%A1n%C3%BD+Slavkov&type=signup"}, +{692,"http://en.wikipedia.org/w/index.php?title=Special:WhatLinksHere/Lady_Anne&namespace=0"}, +{636,"http://en.wikipedia.org/w/index.php?title=Talk:Lady_Anne&action=edit&redlink=1"}, +{628,"http://en.wikipedia.org/w/index.php?title=Template:2002_NBA_Draft&action=edit"}, +{1028,"http://en.wikipedia.org/w/index.php?title=Template:Big_East_Conference_Men%27s_Basketball_Player_of_the_Year_navbox&action=edit"}, +{636,"http://en.wikipedia.org/w/index.php?title=Template:Cartoonist-stub&action=edit"}, +{692,"http://en.wikipedia.org/w/index.php?title=Template:Constitution_of_Turkey&action=edit"}, +{872,"http://en.wikipedia.org/w/index.php?title=Template:Dallas_Mavericks_2010%E2%80%9311_NBA_champions&action=edit"}, +{612,"http://en.wikipedia.org/w/index.php?title=Template:Gene-22-stub&action=edit"}, +{676,"http://en.wikipedia.org/w/index.php?title=Template:Levo%C4%8Da_District&action=edit"}, +{756,"http://en.wikipedia.org/w/index.php?title=Template:Milwaukee_Bucks_current_roster&action=edit"}, +{636,"http://en.wikipedia.org/w/index.php?title=Template:Noctuoidea-stub&action=edit"}, +{580,"http://en.wikipedia.org/w/index.php?title=Template:PBB/1652&action=edit"}, +{604,"http://en.wikipedia.org/w/index.php?title=Template:PDB_Gallery&action=edit"}, +{660,"http://en.wikipedia.org/w/index.php?title=Template:Politics_of_Turkey&action=edit"}, +{676,"http://en.wikipedia.org/w/index.php?title=Template:Pre%C5%A1ov-geo-stub&action=edit"}, +{700,"http://en.wikipedia.org/w/index.php?title=Template:Switzerland-writer-stub&action=edit"}, +{716,"http://en.wikipedia.org/w/index.php?title=Template:The_Swiss_Family_Robinson&action=edit"}, +{700,"http://en.wikipedia.org/w/index.php?title=Template_talk:PBB/1652&action=edit&redlink=1"}, +{836,"http://en.wikipedia.org/w/index.php?title=Template_talk:The_Swiss_Family_Robinson&action=edit&redlink=1"}, +{492,"http://en.wikipedia.org/w/index.php?title=Tumula&action=edit"}, +{572,"http://en.wikipedia.org/w/index.php?title=Tumula&action=edit§ion=1"}, +{516,"http://en.wikipedia.org/w/index.php?title=Tumula&action=history"}, +{492,"http://en.wikipedia.org/w/index.php?title=Tumula&action=info"}, +{496,"http://en.wikipedia.org/w/index.php?title=Tumula&oldid=401070860"}, +{508,"http://en.wikipedia.org/w/index.php?title=Tumula&printable=yes"}, +{508,"http://en.wikipedia.org/w/index.php?title=Tumula&veaction=edit"}, +{588,"http://en.wikipedia.org/w/index.php?title=Tumula&veaction=edit§ion=1"}, +{668,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&action=edit"}, +{748,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&action=edit§ion=1"}, +{692,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&action=history"}, +{668,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&action=info"}, +{672,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&oldid=566504847"}, +{684,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&printable=yes"}, +{684,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&veaction=edit"}, +{764,"http://en.wikipedia.org/w/index.php?title=Turkish_Constitution_of_1921&veaction=edit§ion=1"}, +{724,"http://en.wikipedia.org/w/index.php?title=Turkish_Court_of_Accounts&action=edit&redlink=1"}, +{740,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&action=edit"}, +{820,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&action=edit§ion=1"}, +{764,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&action=history"}, +{740,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&action=info"}, +{744,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&oldid=568532236"}, +{756,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&printable=yes"}, +{756,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&veaction=edit"}, +{836,"http://en.wikipedia.org/w/index.php?title=Vietnam_University_Admission_Rankings&veaction=edit§ion=1"}, +{628,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&action=edit"}, +{708,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&action=edit§ion=1"}, +{652,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&action=history"}, +{628,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&action=info"}, +{632,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&oldid=541325469"}, +{644,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&printable=yes"}, +{644,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&veaction=edit"}, +{724,"http://en.wikipedia.org/w/index.php?title=Vy%C5%A1n%C3%BD_Slavkov&veaction=edit§ion=1"}, +{568,"http://en.wikipedia.org/w/index.php?title=VyÅ¡ný_Slavkov&oldid=541325469"}, +{525,"http://en.wikipedia.org/wiki/%C4%90%E1%BA%AFk_L%E1%BA%AFk_Province"}, +{469,"http://en.wikipedia.org/wiki/%C4%90%E1%BB%93ng_Nai_Province"}, +{685,"http://en.wikipedia.org/wiki/2001%E2%80%9302_NCAA_Division_I_men%27s_basketball_season"}, +{493,"http://en.wikipedia.org/wiki/2002%E2%80%9303_Miami_Heat_season"}, +{437,"http://en.wikipedia.org/wiki/2002%E2%80%9303_NBA_season"}, +{356,"http://en.wikipedia.org/wiki/2002_NBA_Draft"}, +{356,"http://en.wikipedia.org/wiki/2002_NBA_draft"}, +{493,"http://en.wikipedia.org/wiki/2003%E2%80%9304_Miami_Heat_season"}, +{437,"http://en.wikipedia.org/wiki/2003%E2%80%9304_NBA_season"}, +{557,"http://en.wikipedia.org/wiki/2004%E2%80%9305_Los_Angeles_Lakers_season"}, +{437,"http://en.wikipedia.org/wiki/2004%E2%80%9305_NBA_season"}, +{380,"http://en.wikipedia.org/wiki/2004_NBA_Playoffs"}, +{437,"http://en.wikipedia.org/wiki/2005%E2%80%9306_NBA_season"}, +{557,"http://en.wikipedia.org/wiki/2005%E2%80%9306_Washington_Wizards_season"}, +{437,"http://en.wikipedia.org/wiki/2006%E2%80%9307_NBA_season"}, +{557,"http://en.wikipedia.org/wiki/2006%E2%80%9307_Washington_Wizards_season"}, +{364,"http://en.wikipedia.org/wiki/2006_NBA_Finals"}, +{380,"http://en.wikipedia.org/wiki/2006_NBA_Playoffs"}, +{437,"http://en.wikipedia.org/wiki/2007%E2%80%9308_NBA_season"}, +{557,"http://en.wikipedia.org/wiki/2007%E2%80%9308_Washington_Wizards_season"}, +{420,"http://en.wikipedia.org/wiki/2007_NBA_All-Star_Game"}, +{437,"http://en.wikipedia.org/wiki/2008%E2%80%9309_NBA_season"}, +{557,"http://en.wikipedia.org/wiki/2008%E2%80%9309_Washington_Wizards_season"}, +{420,"http://en.wikipedia.org/wiki/2008_NBA_All-Star_Game"}, +{380,"http://en.wikipedia.org/wiki/2008_NBA_Playoffs"}, +{541,"http://en.wikipedia.org/wiki/2009%E2%80%9310_Dallas_Mavericks_season"}, +{437,"http://en.wikipedia.org/wiki/2009%E2%80%9310_NBA_season"}, +{557,"http://en.wikipedia.org/wiki/2009%E2%80%9310_Washington_Wizards_season"}, +{541,"http://en.wikipedia.org/wiki/2010%E2%80%9311_Dallas_Mavericks_season"}, +{437,"http://en.wikipedia.org/wiki/2010%E2%80%9311_NBA_season"}, +{380,"http://en.wikipedia.org/wiki/2010_NBA_Playoffs"}, +{573,"http://en.wikipedia.org/wiki/2011%E2%80%9312_Los_Angeles_Clippers_season"}, +{437,"http://en.wikipedia.org/wiki/2011%E2%80%9312_NBA_season"}, +{364,"http://en.wikipedia.org/wiki/2011_NBA_Finals"}, +{380,"http://en.wikipedia.org/wiki/2011_NBA_Playoffs"}, +{573,"http://en.wikipedia.org/wiki/2012%E2%80%9313_Los_Angeles_Clippers_season"}, +{437,"http://en.wikipedia.org/wiki/2012%E2%80%9313_NBA_season"}, +{380,"http://en.wikipedia.org/wiki/2012_NBA_Playoffs"}, +{437,"http://en.wikipedia.org/wiki/2013%E2%80%9314_NBA_season"}, +{380,"http://en.wikipedia.org/wiki/2013_NBA_Playoffs"}, +{380,"http://en.wikipedia.org/wiki/Abdullah_G%C3%BCl"}, +{572,"http://en.wikipedia.org/wiki/Accession_of_Turkey_to_the_European_Union"}, +{308,"http://en.wikipedia.org/wiki/Adelaide"}, +{332,"http://en.wikipedia.org/wiki/Albert_Pell"}, +{308,"http://en.wikipedia.org/wiki/Alderman"}, +{396,"http://en.wikipedia.org/wiki/Alfredton,_Victoria"}, +{340,"http://en.wikipedia.org/wiki/All_American"}, +{412,"http://en.wikipedia.org/wiki/Allies_of_World_War_I"}, +{364,"http://en.wikipedia.org/wiki/Alonzo_Mourning"}, +{396,"http://en.wikipedia.org/wiki/Amar%27e_Stoudemire"}, +{420,"http://en.wikipedia.org/wiki/Amateur_Athletic_Union"}, +{348,"http://en.wikipedia.org/wiki/Ambrose_Dyson"}, +{356,"http://en.wikipedia.org/wiki/Ambrose_Dyson#"}, +{444,"http://en.wikipedia.org/wiki/Ambrose_Dyson#cite_note-2"}, +{516,"http://en.wikipedia.org/wiki/Ambrose_Dyson#cite_note-lindesay-1"}, +{436,"http://en.wikipedia.org/wiki/Ambrose_Dyson#cite_ref-2"}, +{524,"http://en.wikipedia.org/wiki/Ambrose_Dyson#cite_ref-lindesay_1-0"}, +{524,"http://en.wikipedia.org/wiki/Ambrose_Dyson#cite_ref-lindesay_1-1"}, +{460,"http://en.wikipedia.org/wiki/Ambrose_Dyson#mw-navigation"}, +{420,"http://en.wikipedia.org/wiki/Ambrose_Dyson#p-search"}, +{292,"http://en.wikipedia.org/wiki/Animal"}, +{580,"http://en.wikipedia.org/wiki/Anne,_Duchess_of_Cumberland_and_Strathearn"}, +{324,"http://en.wikipedia.org/wiki/Anne_Bacon"}, +{332,"http://en.wikipedia.org/wiki/Anne_Brewis"}, +{492,"http://en.wikipedia.org/wiki/Anne_Conway,_Viscountess_Conway"}, +{340,"http://en.wikipedia.org/wiki/Anne_Halkett"}, +{316,"http://en.wikipedia.org/wiki/Anne_Hyde"}, +{340,"http://en.wikipedia.org/wiki/Anne_Lambton"}, +{500,"http://en.wikipedia.org/wiki/Anne_Lennard,_Countess_of_Sussex"}, +{500,"http://en.wikipedia.org/wiki/Anne_Stanley,_Countess_of_Ancram"}, +{540,"http://en.wikipedia.org/wiki/Anne_Stanley,_Countess_of_Castlehaven"}, +{332,"http://en.wikipedia.org/wiki/Anne_Wilson"}, +{356,"http://en.wikipedia.org/wiki/Antawn_Jamison"}, +{276,"http://en.wikipedia.org/wiki/Area"}, +{316,"http://en.wikipedia.org/wiki/Arthropod"}, +{396,"http://en.wikipedia.org/wiki/Assist_(basketball)"}, +{436,"http://en.wikipedia.org/wiki/Atat%C3%BCrk%27s_Reforms"}, +{380,"http://en.wikipedia.org/wiki/Authority_control"}, +{669,"http://en.wikipedia.org/wiki/B%C3%A0_R%E1%BB%8Ba%E2%80%93V%C5%A9ng_T%C3%A0u_Province"}, +{520,"http://en.wikipedia.org/wiki/B%C3%ACnh_%C4%90%E1%BB%8Bnh_Province"}, +{528,"http://en.wikipedia.org/wiki/B%C3%ACnh_Ph%C6%B0%E1%BB%9Bc_Province"}, +{450,"http://en.wikipedia.org/wiki/B%E1%BA%AFc_Giang_Province"}, +{442,"http://en.wikipedia.org/wiki/B%E1%BA%AFc_Ninh_Province"}, +{308,"http://en.wikipedia.org/wiki/Baldovce"}, +{308,"http://en.wikipedia.org/wiki/Ballarat"}, +{388,"http://en.wikipedia.org/wiki/Ballarat,_Victoria"}, +{364,"http://en.wikipedia.org/wiki/Baron_Roborough"}, +{324,"http://en.wikipedia.org/wiki/Basketball"}, +{316,"http://en.wikipedia.org/wiki/Beharovce"}, +{356,"http://en.wikipedia.org/wiki/Ben_Hansbrough"}, +{380,"http://en.wikipedia.org/wiki/Benjamin_Disraeli"}, +{476,"http://en.wikipedia.org/wiki/Beverly_Hills_Family_Robinson"}, +{539,"http://en.wikipedia.org/wiki/Big_East_Conference_(1979%E2%80%932013)"}, +{700,"http://en.wikipedia.org/wiki/Big_East_Conference_Men%27s_Basketball_Player_of_the_Year"}, +{316,"http://en.wikipedia.org/wiki/Bijacovce"}, +{644,"http://en.wikipedia.org/wiki/Bill_Russell_NBA_Finals_Most_Valuable_Player_Award"}, +{332,"http://en.wikipedia.org/wiki/Billy_Owens"}, +{444,"http://en.wikipedia.org/wiki/Biological_classification"}, +{388,"http://en.wikipedia.org/wiki/Block_(basketball)"}, +{284,"http://en.wikipedia.org/wiki/Blogs"}, +{404,"http://en.wikipedia.org/wiki/Bo%C5%A1tjan_Nachbar"}, +{324,"http://en.wikipedia.org/wiki/Bob_Bender"}, +{356,"http://en.wikipedia.org/wiki/Brandin_Knight"}, +{460,"http://en.wikipedia.org/wiki/Brandon_Knight_(basketball)"}, +{364,"http://en.wikipedia.org/wiki/Brendan_Haywood"}, +{356,"http://en.wikipedia.org/wiki/Brian_Cardinal"}, +{332,"http://en.wikipedia.org/wiki/Brian_Grant"}, +{308,"http://en.wikipedia.org/wiki/Brutovce"}, +{308,"http://en.wikipedia.org/wiki/Buglovce"}, +{332,"http://en.wikipedia.org/wiki/Burger_King"}, +{340,"http://en.wikipedia.org/wiki/C._J._Dennis"}, +{380,"http://en.wikipedia.org/wiki/Cabinet_of_Turkey"}, +{292,"http://en.wikipedia.org/wiki/Caliph"}, +{316,"http://en.wikipedia.org/wiki/Caliphate"}, +{372,"http://en.wikipedia.org/wiki/Carlo_Pellegrini"}, +{348,"http://en.wikipedia.org/wiki/Carlos_Boozer"}, +{356,"http://en.wikipedia.org/wiki/Carlos_Delfino"}, +{340,"http://en.wikipedia.org/wiki/Caron_Butler"}, +{348,"http://en.wikipedia.org/wiki/Caron_Butler#"}, +{460,"http://en.wikipedia.org/wiki/Caron_Butler#College_career"}, +{428,"http://en.wikipedia.org/wiki/Caron_Butler#Early_life"}, +{460,"http://en.wikipedia.org/wiki/Caron_Butler#External_links"}, +{428,"http://en.wikipedia.org/wiki/Caron_Butler#NBA_career"}, +{516,"http://en.wikipedia.org/wiki/Caron_Butler#NBA_career_statistics"}, +{452,"http://en.wikipedia.org/wiki/Caron_Butler#Personal_life"}, +{412,"http://en.wikipedia.org/wiki/Caron_Butler#Playoffs"}, +{428,"http://en.wikipedia.org/wiki/Caron_Butler#References"}, +{460,"http://en.wikipedia.org/wiki/Caron_Butler#Regular_season"}, +{444,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-10"}, +{436,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-5"}, +{524,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-AllStories-7"}, +{466,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-BK-20"}, +{492,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-oprah1-1"}, +{492,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-oprah2-2"}, +{492,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-straws-3"}, +{524,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-toughjuice-8"}, +{516,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-washtimes-9"}, +{556,"http://en.wikipedia.org/wiki/Caron_Butler#cite_note-wp-greatescape-4"}, +{436,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-10"}, +{428,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-5"}, +{532,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-AllStories_7-0"}, +{532,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-AllStories_7-1"}, +{476,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-BK_20-0"}, +{476,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-BK_20-1"}, +{500,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-oprah1_1-0"}, +{500,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-oprah2_2-0"}, +{500,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-straws_3-0"}, +{500,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-straws_3-1"}, +{500,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-straws_3-2"}, +{532,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-toughjuice_8-0"}, +{524,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-washtimes_9-0"}, +{564,"http://en.wikipedia.org/wiki/Caron_Butler#cite_ref-wp-greatescape_4-0"}, +{452,"http://en.wikipedia.org/wiki/Caron_Butler#mw-navigation"}, +{412,"http://en.wikipedia.org/wiki/Caron_Butler#p-search"}, +{324,"http://en.wikipedia.org/wiki/Cartoonist"}, +{356,"http://en.wikipedia.org/wiki/Casey_Jacobsen"}, +{404,"http://en.wikipedia.org/wiki/Category:1743_births"}, +{404,"http://en.wikipedia.org/wiki/Category:1818_births"}, +{404,"http://en.wikipedia.org/wiki/Category:1818_deaths"}, +{404,"http://en.wikipedia.org/wiki/Category:1876_births"}, +{404,"http://en.wikipedia.org/wiki/Category:1908_deaths"}, +{404,"http://en.wikipedia.org/wiki/Category:1913_deaths"}, +{524,"http://en.wikipedia.org/wiki/Category:1921_in_the_Ottoman_Empire"}, +{404,"http://en.wikipedia.org/wiki/Category:1980_births"}, +{492,"http://en.wikipedia.org/wiki/Category:19th-century_novelists"}, +{576,"http://en.wikipedia.org/wiki/Category:Accuracy_disputes_from_March_2012"}, +{596,"http://en.wikipedia.org/wiki/Category:African-American_basketball_players"}, +{572,"http://en.wikipedia.org/wiki/Category:All_article_disambiguation_pages"}, +{636,"http://en.wikipedia.org/wiki/Category:All_articles_lacking_reliable_references"}, +{652,"http://en.wikipedia.org/wiki/Category:All_articles_needing_additional_references"}, +{572,"http://en.wikipedia.org/wiki/Category:All_articles_needing_coordinates"}, +{532,"http://en.wikipedia.org/wiki/Category:All_articles_to_be_expanded"}, +{620,"http://en.wikipedia.org/wiki/Category:All_articles_with_unsourced_statements"}, +{508,"http://en.wikipedia.org/wiki/Category:All_disambiguation_pages"}, +{620,"http://en.wikipedia.org/wiki/Category:All_pages_needing_factual_verification"}, +{644,"http://en.wikipedia.org/wiki/Category:Articles_containing_Turkish-language_text"}, +{752,"http://en.wikipedia.org/wiki/Category:Articles_lacking_reliable_references_from_February_2013"}, +{760,"http://en.wikipedia.org/wiki/Category:Articles_needing_additional_references_from_January_2011"}, +{716,"http://en.wikipedia.org/wiki/Category:Articles_needing_translation_from_German_Wikipedia"}, +{632,"http://en.wikipedia.org/wiki/Category:Articles_to_be_expanded_from_August_2013"}, +{636,"http://en.wikipedia.org/wiki/Category:Articles_with_%27species%27_microformats"}, +{744,"http://en.wikipedia.org/wiki/Category:Articles_with_unsourced_statements_from_September_2010"}, +{492,"http://en.wikipedia.org/wiki/Category:Australian_cartoonists"}, +{500,"http://en.wikipedia.org/wiki/Category:Australian_illustrators"}, +{476,"http://en.wikipedia.org/wiki/Category:Australian_satirists"}, +{700,"http://en.wikipedia.org/wiki/Category:Baronets_in_the_Baronetage_of_the_United_Kingdom"}, +{580,"http://en.wikipedia.org/wiki/Category:Basketball_players_from_Wisconsin"}, +{444,"http://en.wikipedia.org/wiki/Category:Cartoonist_stubs"}, +{524,"http://en.wikipedia.org/wiki/Category:Cartoonists_from_Melbourne"}, +{508,"http://en.wikipedia.org/wiki/Category:Chromosome_22_gene_stubs"}, +{684,"http://en.wikipedia.org/wiki/Category:Connecticut_Huskies_men%27s_basketball_players"}, +{532,"http://en.wikipedia.org/wiki/Category:Conservative_Party_(UK)_MPs"}, +{500,"http://en.wikipedia.org/wiki/Category:Constitutions_of_Turkey"}, +{508,"http://en.wikipedia.org/wiki/Category:Dallas_Mavericks_players"}, +{484,"http://en.wikipedia.org/wiki/Category:Defunct_constitutions"}, +{476,"http://en.wikipedia.org/wiki/Category:Disambiguation_pages"}, +{492,"http://en.wikipedia.org/wiki/Category:High_Sheriffs_of_Devon"}, +{620,"http://en.wikipedia.org/wiki/Category:High_schools_for_the_gifted_in_Vietnam"}, +{500,"http://en.wikipedia.org/wiki/Category:High_schools_in_Vietnam"}, +{428,"http://en.wikipedia.org/wiki/Category:Human_proteins"}, +{420,"http://en.wikipedia.org/wiki/Category:Living_people"}, +{540,"http://en.wikipedia.org/wiki/Category:Los_Angeles_Clippers_players"}, +{524,"http://en.wikipedia.org/wiki/Category:Los_Angeles_Lakers_players"}, +{852,"http://en.wikipedia.org/wiki/Category:Members_of_the_United_Kingdom_Parliament_for_English_constituencies"}, +{492,"http://en.wikipedia.org/wiki/Category:Miami_Heat_draft_picks"}, +{460,"http://en.wikipedia.org/wiki/Category:Miami_Heat_players"}, +{428,"http://en.wikipedia.org/wiki/Category:Micronoctuidae"}, +{644,"http://en.wikipedia.org/wiki/Category:National_Basketball_Association_All-Stars"}, +{444,"http://en.wikipedia.org/wiki/Category:Noctuoidea_stubs"}, +{556,"http://en.wikipedia.org/wiki/Category:Pages_with_no_translate_target"}, +{444,"http://en.wikipedia.org/wiki/Category:People_from_Bern"}, +{548,"http://en.wikipedia.org/wiki/Category:People_from_Racine,_Wisconsin"}, +{588,"http://en.wikipedia.org/wiki/Category:Pre%C5%A1ov_Region_geography_stubs"}, +{460,"http://en.wikipedia.org/wiki/Category:Schools_in_Vietnam"}, +{436,"http://en.wikipedia.org/wiki/Category:Shooting_guards"}, +{428,"http://en.wikipedia.org/wiki/Category:Small_forwards"}, +{386,"http://en.wikipedia.org/wiki/Category:Spi%C5%A1"}, +{524,"http://en.wikipedia.org/wiki/Category:Swiss_children%27s_writers"}, +{436,"http://en.wikipedia.org/wiki/Category:Swiss_novelists"}, +{460,"http://en.wikipedia.org/wiki/Category:Swiss_writer_stubs"}, +{479,"http://en.wikipedia.org/wiki/Category:UK_MPs_1857%E2%80%931859"}, +{479,"http://en.wikipedia.org/wiki/Category:UK_MPs_1859%E2%80%931865"}, +{479,"http://en.wikipedia.org/wiki/Category:UK_MPs_1868%E2%80%931874"}, +{479,"http://en.wikipedia.org/wiki/Category:UK_MPs_1874%E2%80%931880"}, +{479,"http://en.wikipedia.org/wiki/Category:UK_MPs_1880%E2%80%931885"}, +{548,"http://en.wikipedia.org/wiki/Category:United_States_Navy_ship_names"}, +{592,"http://en.wikipedia.org/wiki/Category:Use_British_English_from_March_2012"}, +{560,"http://en.wikipedia.org/wiki/Category:Use_dmy_dates_from_January_2012"}, +{536,"http://en.wikipedia.org/wiki/Category:Use_dmy_dates_from_July_2013"}, +{660,"http://en.wikipedia.org/wiki/Category:Vietnam_articles_missing_geocoordinate_data"}, +{724,"http://en.wikipedia.org/wiki/Category:Villages_and_municipalities_in_Levo%C4%8Da_District"}, +{524,"http://en.wikipedia.org/wiki/Category:Washington_Wizards_players"}, +{964,"http://en.wikipedia.org/wiki/Category:Wikipedia_articles_incorporating_an_LRPP-Bt_template_without_an_unnamed_parameter"}, +{816,"http://en.wikipedia.org/wiki/Category:Wikipedia_articles_needing_factual_verification_from_March_2012"}, +{848,"http://en.wikipedia.org/wiki/Category:Wikipedia_articles_needing_page_number_citations_from_February_2013"}, +{636,"http://en.wikipedia.org/wiki/Category:Wikipedia_articles_with_VIAF_identifiers"}, +{412,"http://en.wikipedia.org/wiki/Cemil_%C3%87i%C3%A7ek"}, +{540,"http://en.wikipedia.org/wiki/Charles_Smith_(basketball,_born_1965)"}, +{540,"http://en.wikipedia.org/wiki/Charles_Smith_(basketball,_born_1967)"}, +{364,"http://en.wikipedia.org/wiki/Chris_Jefferies"}, +{444,"http://en.wikipedia.org/wiki/Chris_Mullin_(basketball)"}, +{436,"http://en.wikipedia.org/wiki/Chris_Owens_(basketball)"}, +{340,"http://en.wikipedia.org/wiki/Chris_Wilcox"}, +{348,"http://en.wikipedia.org/wiki/Chromosome_22"}, +{348,"http://en.wikipedia.org/wiki/Chucky_Atkins"}, +{380,"http://en.wikipedia.org/wiki/Clare_Sewell_Read"}, +{396,"http://en.wikipedia.org/wiki/Cleveland_Cavaliers"}, +{548,"http://en.wikipedia.org/wiki/Connecticut_Huskies_men%27s_basketball"}, +{499,"http://en.wikipedia.org/wiki/Conservative_Government_1874-1880"}, +{428,"http://en.wikipedia.org/wiki/Conservative_Party_(UK)"}, +{340,"http://en.wikipedia.org/wiki/Constitution"}, +{420,"http://en.wikipedia.org/wiki/Constitution_of_Turkey"}, +{484,"http://en.wikipedia.org/wiki/Constitutional_Court_of_Turkey"}, +{500,"http://en.wikipedia.org/wiki/Constitutional_history_of_Turkey"}, +{428,"http://en.wikipedia.org/wiki/Constitutional_monarchy"}, +{340,"http://en.wikipedia.org/wiki/Corey_Brewer"}, +{364,"http://en.wikipedia.org/wiki/Corsley_Edwards"}, +{460,"http://en.wikipedia.org/wiki/Court_of_Cassation_(Turkey)"}, +{372,"http://en.wikipedia.org/wiki/Curtis_Borchardt"}, +{516,"http://en.wikipedia.org/wiki/D%C3%BAbrava,_Levo%C4%8Da_District"}, +{324,"http://en.wikipedia.org/wiki/DDT_(gene)"}, +{332,"http://en.wikipedia.org/wiki/DDT_(gene)#"}, +{476,"http://en.wikipedia.org/wiki/DDT_(gene)#cite_note-entrez-3"}, +{506,"http://en.wikipedia.org/wiki/DDT_(gene)#cite_note-pmid9480844-1"}, +{484,"http://en.wikipedia.org/wiki/DDT_(gene)#cite_ref-entrez_3-0"}, +{484,"http://en.wikipedia.org/wiki/DDT_(gene)#cite_ref-entrez_3-1"}, +{518,"http://en.wikipedia.org/wiki/DDT_(gene)#cite_ref-pmid9480844_1-0"}, +{436,"http://en.wikipedia.org/wiki/DDT_(gene)#mw-navigation"}, +{396,"http://en.wikipedia.org/wiki/DDT_(gene)#p-search"}, +{300,"http://en.wikipedia.org/wiki/Da_Nang"}, +{348,"http://en.wikipedia.org/wiki/Dajuan_Wagner"}, +{372,"http://en.wikipedia.org/wiki/Dallas_Mavericks"}, +{372,"http://en.wikipedia.org/wiki/Dan_Callandrillo"}, +{324,"http://en.wikipedia.org/wiki/Dan_Dickau"}, +{340,"http://en.wikipedia.org/wiki/Dan_Gadzuric"}, +{340,"http://en.wikipedia.org/wiki/Daniel_Defoe"}, +{364,"http://en.wikipedia.org/wiki/Darius_Songaila"}, +{380,"http://en.wikipedia.org/wiki/Darrell_Armstrong"}, +{300,"http://en.wikipedia.org/wiki/Das_Bus"}, +{356,"http://en.wikipedia.org/wiki/David_Andersen"}, +{340,"http://en.wikipedia.org/wiki/DeJuan_Blair"}, +{380,"http://en.wikipedia.org/wiki/DeShawn_Stevenson"}, +{364,"http://en.wikipedia.org/wiki/Derrick_Coleman"}, +{380,"http://en.wikipedia.org/wiki/Deshawn_Stevenson"}, +{444,"http://en.wikipedia.org/wiki/Digital_object_identifier"}, +{348,"http://en.wikipedia.org/wiki/Dirk_Nowitzki"}, +{447,"http://en.wikipedia.org/wiki/Dlh%C3%A9_Str%C3%A1%C5%BEe"}, +{508,"http://en.wikipedia.org/wiki/Do%C4%BEany,_Levo%C4%8Da_District"}, +{356,"http://en.wikipedia.org/wiki/Doma%C5%88ovce"}, +{364,"http://en.wikipedia.org/wiki/Dominique_Jones"}, +{372,"http://en.wikipedia.org/wiki/Donyell_Marshall"}, +{292,"http://en.wikipedia.org/wiki/Dravce"}, +{332,"http://en.wikipedia.org/wiki/Drew_Gooden"}, +{364,"http://en.wikipedia.org/wiki/Duke_University"}, +{332,"http://en.wikipedia.org/wiki/Dwane_Casey"}, +{436,"http://en.wikipedia.org/wiki/Eastern_Conference_(NBA)"}, +{380,"http://en.wikipedia.org/wiki/Economy_of_Turkey"}, +{444,"http://en.wikipedia.org/wiki/Eddie_Jordan_(basketball)"}, +{404,"http://en.wikipedia.org/wiki/Edward_Ambrose_Dyson"}, +{340,"http://en.wikipedia.org/wiki/Edward_Dyson"}, +{316,"http://en.wikipedia.org/wiki/Ekpe_Udoh"}, +{396,"http://en.wikipedia.org/wiki/Elections_in_Turkey"}, +{540,"http://en.wikipedia.org/wiki/Elections_in_Turkey#General_elections"}, +{524,"http://en.wikipedia.org/wiki/Elections_in_Turkey#Local_elections"}, +{316,"http://en.wikipedia.org/wiki/Elevation"}, +{300,"http://en.wikipedia.org/wiki/Elite_8"}, +{340,"http://en.wikipedia.org/wiki/Emeka_Okafor"}, +{300,"http://en.wikipedia.org/wiki/Ensembl"}, +{356,"http://en.wikipedia.org/wiki/Entente_powers"}, +{292,"http://en.wikipedia.org/wiki/Entrez"}, +{292,"http://en.wikipedia.org/wiki/Enzyme"}, +{436,"http://en.wikipedia.org/wiki/Enzyme_Commission_number"}, +{436,"http://en.wikipedia.org/wiki/Erdo%C4%9Fan_III_Cabinet"}, +{340,"http://en.wikipedia.org/wiki/Eric_Bledsoe"}, +{396,"http://en.wikipedia.org/wiki/Ersan_%C4%B0lyasova"}, +{580,"http://en.wikipedia.org/wiki/Establishment_of_Turkish_national_movement"}, +{604,"http://en.wikipedia.org/wiki/European_Union_%E2%80%93_Turkey_Customs_Union"}, +{420,"http://en.wikipedia.org/wiki/Executive_(government)"}, +{500,"http://en.wikipedia.org/wiki/FIBA_Under-21_World_Championship"}, +{372,"http://en.wikipedia.org/wiki/Family_(biology)"}, +{396,"http://en.wikipedia.org/wiki/Federico_Kammerichs"}, +{428,"http://en.wikipedia.org/wiki/Field_goal_(basketball)"}, +{484,"http://en.wikipedia.org/wiki/File:A_coloured_voting_box.svg"}, +{508,"http://en.wikipedia.org/wiki/File:Bryant_Fades_Over_Butler.jpg"}, +{412,"http://en.wikipedia.org/wiki/File:Caron_Butler.JPG"}, +{428,"http://en.wikipedia.org/wiki/File:Creatorballoon.png"}, +{380,"http://en.wikipedia.org/wiki/File:DNA_stub.png"}, +{420,"http://en.wikipedia.org/wiki/File:Disambig_gray.svg"}, +{428,"http://en.wikipedia.org/wiki/File:Flag_of_Turkey.svg"}, +{610,"http://en.wikipedia.org/wiki/File:Massey_Lopes,_Vanity_Fair,_1875-05-15.jpg"}, +{468,"http://en.wikipedia.org/wiki/File:Noctua.pronuba.7199.jpg"}, +{412,"http://en.wikipedia.org/wiki/File:Okres_levoca.png"}, +{514,"http://en.wikipedia.org/wiki/File:PBB_GE_DDT_202929_s_at_tn.png"}, +{412,"http://en.wikipedia.org/wiki/File:PDB_1dpt_EBI.jpg"}, +{356,"http://en.wikipedia.org/wiki/File:P_vip.svg"}, +{476,"http://en.wikipedia.org/wiki/File:Protein_DDT_PDB_1dpt.png"}, +{420,"http://en.wikipedia.org/wiki/File:Quill_and_ink.svg"}, +{460,"http://en.wikipedia.org/wiki/File:Slovakiatynk%C3%A4.svg"}, +{412,"http://en.wikipedia.org/wiki/File:Speaker_Icon.svg"}, +{540,"http://en.wikipedia.org/wiki/File:Translation_to_english_arrow.svg"}, +{436,"http://en.wikipedia.org/wiki/File:Wikisource-logo.svg"}, +{524,"http://en.wikipedia.org/wiki/Financial_Secretary_to_the_Treasury"}, +{524,"http://en.wikipedia.org/wiki/Foreign_Language_Specialized_School"}, +{460,"http://en.wikipedia.org/wiki/Foreign_relations_of_Turkey"}, +{564,"http://en.wikipedia.org/wiki/Francis_Cottington,_1st_Baron_Cottington"}, +{460,"http://en.wikipedia.org/wiki/Frank_Williams_(basketball)"}, +{428,"http://en.wikipedia.org/wiki/Fred_Jones_(basketball)"}, +{324,"http://en.wikipedia.org/wiki/Free_throw"}, +{456,"http://en.wikipedia.org/wiki/French_Constitution_of_1791"}, +{316,"http://en.wikipedia.org/wiki/Gary_Neal"}, +{276,"http://en.wikipedia.org/wiki/Gene"}, +{316,"http://en.wikipedia.org/wiki/GeneCards"}, +{348,"http://en.wikipedia.org/wiki/Gene_Ontology"}, +{284,"http://en.wikipedia.org/wiki/Genus"}, +{468,"http://en.wikipedia.org/wiki/Geographic_coordinate_system"}, +{412,"http://en.wikipedia.org/wiki/Geography_of_Slovakia"}, +{412,"http://en.wikipedia.org/wiki/Giannis_Antetokounmpo"}, +{356,"http://en.wikipedia.org/wiki/Gilbert_Arenas"}, +{396,"http://en.wikipedia.org/wiki/Gran%C4%8D-Petrovce"}, +{508,"http://en.wikipedia.org/wiki/Grand_National_Assembly_of_Turkey"}, +{412,"http://en.wikipedia.org/wiki/Great_Western_Railway"}, +{404,"http://en.wikipedia.org/wiki/H%C3%A0_Nam_Province"}, +{452,"http://en.wikipedia.org/wiki/H%C3%A0_T%C4%A9nh_Province"}, +{460,"http://en.wikipedia.org/wiki/H%C6%B0ng_Y%C3%AAn_Province"}, +{523,"http://en.wikipedia.org/wiki/H%E1%BA%A3i_D%C6%B0%C6%A1ng_Province"}, +{316,"http://en.wikipedia.org/wiki/Hai_Phong"}, +{348,"http://en.wikipedia.org/wiki/Hakim_Warrick"}, +{284,"http://en.wikipedia.org/wiki/Hanoi"}, +{540,"http://en.wikipedia.org/wiki/Hanoi_%E2%80%93_Amsterdam_High_School"}, +{316,"http://en.wikipedia.org/wiki/Harakovce"}, +{364,"http://en.wikipedia.org/wiki/Hasheem_Thabeet"}, +{348,"http://en.wikipedia.org/wiki/Help:Category"}, +{348,"http://en.wikipedia.org/wiki/Help:Contents"}, +{396,"http://en.wikipedia.org/wiki/Help:Disambiguation"}, +{396,"http://en.wikipedia.org/wiki/Help:IPA_for_German"}, +{516,"http://en.wikipedia.org/wiki/Help:Introduction_to_referencing/1"}, +{524,"http://en.wikipedia.org/wiki/Henry_Chaplin,_1st_Viscount_Chaplin"}, +{476,"http://en.wikipedia.org/wiki/Henry_Lopes,_1st_Baron_Ludlow"}, +{500,"http://en.wikipedia.org/wiki/Henry_Lopes,_1st_Baron_Roborough"}, +{604,"http://en.wikipedia.org/wiki/Her_Majesty%27s_Most_Honourable_Privy_Council"}, +{812,"http://en.wikipedia.org/wiki/High_School_for_Gifted_Students,_Hanoi_National_University_of_Education"}, +{724,"http://en.wikipedia.org/wiki/High_School_for_Gifted_Students,_Hanoi_University_of_Science"}, +{452,"http://en.wikipedia.org/wiki/High_School_for_the_Gifted"}, +{412,"http://en.wikipedia.org/wiki/High_Sheriff_of_Devon"}, +{300,"http://en.wikipedia.org/wiki/History"}, +{380,"http://en.wikipedia.org/wiki/History_of_Turkey"}, +{572,"http://en.wikipedia.org/wiki/History_of_Turkish_presidential_elections"}, +{372,"http://en.wikipedia.org/wiki/Ho_Chi_Minh_City"}, +{324,"http://en.wikipedia.org/wiki/HomoloGene"}, +{444,"http://en.wikipedia.org/wiki/Human_Genome_Organisation"}, +{332,"http://en.wikipedia.org/wiki/Ian_Mahinmi"}, +{292,"http://en.wikipedia.org/wiki/Insect"}, +{372,"http://en.wikipedia.org/wiki/Internet_Archive"}, +{316,"http://en.wikipedia.org/wiki/Ish_Smith"}, +{332,"http://en.wikipedia.org/wiki/Islamic_Law"}, +{340,"http://en.wikipedia.org/wiki/J._J._Redick"}, +{308,"http://en.wikipedia.org/wiki/Jablonov"}, +{332,"http://en.wikipedia.org/wiki/Jae_Crowder"}, +{348,"http://en.wikipedia.org/wiki/Jamal_Sampson"}, +{468,"http://en.wikipedia.org/wiki/James_Singleton_(basketball)"}, +{468,"http://en.wikipedia.org/wiki/James_Wilson_(UK_politician)"}, +{340,"http://en.wikipedia.org/wiki/Jared_Dudley"}, +{356,"http://en.wikipedia.org/wiki/Jared_Jeffries"}, +{460,"http://en.wikipedia.org/wiki/Jason_Jennings_(basketball)"}, +{324,"http://en.wikipedia.org/wiki/Jason_Kidd"}, +{332,"http://en.wikipedia.org/wiki/Jason_Terry"}, +{444,"http://en.wikipedia.org/wiki/Jay_Williams_(basketball)"}, +{428,"http://en.wikipedia.org/wiki/Jeff_Green_(basketball)"}, +{407,"http://en.wikipedia.org/wiki/Ji%C5%99%C3%AD_Welsch"}, +{332,"http://en.wikipedia.org/wiki/Jim_Calhoun"}, +{340,"http://en.wikipedia.org/wiki/Jim_Cleamons"}, +{380,"http://en.wikipedia.org/wiki/Johann_David_Wyss"}, +{388,"http://en.wikipedia.org/wiki/Johann_David_Wyss#"}, +{476,"http://en.wikipedia.org/wiki/Johann_David_Wyss#cite_note-1"}, +{468,"http://en.wikipedia.org/wiki/Johann_David_Wyss#cite_ref-1"}, +{492,"http://en.wikipedia.org/wiki/Johann_David_Wyss#mw-navigation"}, +{452,"http://en.wikipedia.org/wiki/Johann_David_Wyss#p-search"}, +{388,"http://en.wikipedia.org/wiki/Johann_Rudolf_Wyss"}, +{436,"http://en.wikipedia.org/wiki/John_Bagley_(basketball)"}, +{420,"http://en.wikipedia.org/wiki/John_Carpenter_Garnier"}, +{324,"http://en.wikipedia.org/wiki/John_Duren"}, +{436,"http://en.wikipedia.org/wiki/John_Henson_(basketball)"}, +{380,"http://en.wikipedia.org/wiki/John_Lewis_Phipps"}, +{492,"http://en.wikipedia.org/wiki/John_Russell,_Viscount_Amberley"}, +{340,"http://en.wikipedia.org/wiki/John_Salmons"}, +{460,"http://en.wikipedia.org/wiki/John_Tremayne_(1825_-_1901)"}, +{540,"http://en.wikipedia.org/wiki/John_Yarde-Buller,_1st_Baron_Churston"}, +{404,"http://en.wikipedia.org/wiki/Jos%C3%A9_Juan_Barea"}, +{332,"http://en.wikipedia.org/wiki/Josh_Howard"}, +{500,"http://en.wikipedia.org/wiki/Juan_Carlos_Navarro_(basketball)"}, +{324,"http://en.wikipedia.org/wiki/Juan_Dixon"}, +{332,"http://en.wikipedia.org/wiki/Kareem_Rush"}, +{543,"http://en.wikipedia.org/wiki/Kemal_K%C4%B1l%C4%B1%C3%A7daro%C4%9Flu"}, +{348,"http://en.wikipedia.org/wiki/Kerry_Kittles"}, +{324,"http://en.wikipedia.org/wiki/Kew_Asylum"}, +{468,"http://en.wikipedia.org/wiki/Kh%C3%A1nh_H%C3%B2a_Province"}, +{364,"http://en.wikipedia.org/wiki/Khris_Middleton"}, +{324,"http://en.wikipedia.org/wiki/Kl%C4%8Dov"}, +{332,"http://en.wikipedia.org/wiki/Kobe_Bryant"}, +{338,"http://en.wikipedia.org/wiki/Korytn%C3%A9"}, +{308,"http://en.wikipedia.org/wiki/Kurimany"}, +{332,"http://en.wikipedia.org/wiki/Kwame_Brown"}, +{530,"http://en.wikipedia.org/wiki/L%C3%BA%C4%8Dka,_Levo%C4%8Da_District"}, +{316,"http://en.wikipedia.org/wiki/Lady_Anne"}, +{324,"http://en.wikipedia.org/wiki/Lady_Anne#"}, +{484,"http://en.wikipedia.org/wiki/Lady_Anne#Fictional_characters"}, +{372,"http://en.wikipedia.org/wiki/Lady_Anne#People"}, +{388,"http://en.wikipedia.org/wiki/Lady_Anne#See_also"}, +{364,"http://en.wikipedia.org/wiki/Lady_Anne#Ships"}, +{428,"http://en.wikipedia.org/wiki/Lady_Anne#mw-navigation"}, +{388,"http://en.wikipedia.org/wiki/Lady_Anne#p-search"}, +{412,"http://en.wikipedia.org/wiki/Lady_Anne-Marie_Byrne"}, +{380,"http://en.wikipedia.org/wiki/Lady_Anne_Barnard"}, +{364,"http://en.wikipedia.org/wiki/Lady_Anne_Berry"}, +{364,"http://en.wikipedia.org/wiki/Lady_Anne_Blunt"}, +{468,"http://en.wikipedia.org/wiki/Lady_Anne_Cavendish-Bentinck"}, +{396,"http://en.wikipedia.org/wiki/Lady_Anne_Churchill"}, +{388,"http://en.wikipedia.org/wiki/Lady_Anne_Clifford"}, +{500,"http://en.wikipedia.org/wiki/Lady_Anne_Farquharson-MacKintosh"}, +{356,"http://en.wikipedia.org/wiki/Lady_Anne_Rhys"}, +{396,"http://en.wikipedia.org/wiki/Lam_Son_High_School"}, +{324,"http://en.wikipedia.org/wiki/Lamar_Odom"}, +{340,"http://en.wikipedia.org/wiki/Laron_Profit"}, +{324,"http://en.wikipedia.org/wiki/Larry_Drew"}, +{452,"http://en.wikipedia.org/wiki/Larry_Sanders_(basketball)"}, +{492,"http://en.wikipedia.org/wiki/Lawrence_Palk,_1st_Baron_Haldon"}, +{340,"http://en.wikipedia.org/wiki/LeBron_James"}, +{444,"http://en.wikipedia.org/wiki/Le_Hong_Phong_High_School"}, +{556,"http://en.wikipedia.org/wiki/Leader_of_the_Main_Opposition_of_Turkey"}, +{548,"http://en.wikipedia.org/wiki/Legal_System_in_the_Republic_of_Turkey"}, +{756,"http://en.wikipedia.org/wiki/Legal_System_in_the_Republic_of_Turkey#Turkish_Court_of_Accounts"}, +{548,"http://en.wikipedia.org/wiki/Legal_system_of_the_Republic_of_Turkey"}, +{332,"http://en.wikipedia.org/wiki/Legislative"}, +{332,"http://en.wikipedia.org/wiki/Lepidoptera"}, +{332,"http://en.wikipedia.org/wiki/Levo%C4%8Da"}, +{404,"http://en.wikipedia.org/wiki/Levo%C4%8Da_District"}, +{308,"http://en.wikipedia.org/wiki/LibriVox"}, +{412,"http://en.wikipedia.org/wiki/List_of_NBA_champions"}, +{468,"http://en.wikipedia.org/wiki/List_of_Presidents_of_Turkey"}, +{692,"http://en.wikipedia.org/wiki/List_of_Presidents_of_the_Constitutional_Court_of_Turkey"}, +{508,"http://en.wikipedia.org/wiki/List_of_Prime_Ministers_of_Turkey"}, +{596,"http://en.wikipedia.org/wiki/List_of_Speakers_of_the_Parliament_of_Turkey"}, +{444,"http://en.wikipedia.org/wiki/List_of_Turkish_diplomats"}, +{540,"http://en.wikipedia.org/wiki/List_of_diplomatic_missions_of_Turkey"}, +{452,"http://en.wikipedia.org/wiki/List_of_extant_baronetcies"}, +{524,"http://en.wikipedia.org/wiki/List_of_political_parties_in_Turkey"}, +{372,"http://en.wikipedia.org/wiki/Long_An_Province"}, +{340,"http://en.wikipedia.org/wiki/Lonny_Baxter"}, +{516,"http://en.wikipedia.org/wiki/Lord_Commissioner_of_the_Admiralty"}, +{404,"http://en.wikipedia.org/wiki/Los_Angeles_Clippers"}, +{388,"http://en.wikipedia.org/wiki/Los_Angeles_Lakers"}, +{348,"http://en.wikipedia.org/wiki/Lost_in_Space"}, +{324,"http://en.wikipedia.org/wiki/Luis_Scola"}, +{356,"http://en.wikipedia.org/wiki/Luke_Harangody"}, +{340,"http://en.wikipedia.org/wiki/Luke_Ridnour"}, +{548,"http://en.wikipedia.org/wiki/Macrophage_migration_inhibitory_factor"}, +{604,"http://en.wikipedia.org/wiki/Macrophage_migration_inhibitory_factor_domain"}, +{316,"http://en.wikipedia.org/wiki/Main_Page"}, +{428,"http://en.wikipedia.org/wiki/Maine_Central_Institute"}, +{356,"http://en.wikipedia.org/wiki/Marcus_Haislip"}, +{348,"http://en.wikipedia.org/wiki/Marcus_Taylor"}, +{332,"http://en.wikipedia.org/wiki/Mario_Kasun"}, +{388,"http://en.wikipedia.org/wiki/Maryland_Terrapins"}, +{332,"http://en.wikipedia.org/wiki/Matt_Barnes"}, +{372,"http://en.wikipedia.org/wiki/Melbourne_Herald"}, +{364,"http://en.wikipedia.org/wiki/Melbourne_Punch"}, +{324,"http://en.wikipedia.org/wiki/Melvin_Ely"}, +{468,"http://en.wikipedia.org/wiki/Mendelian_Inheritance_in_Man"}, +{324,"http://en.wikipedia.org/wiki/Miami_Heat"}, +{356,"http://en.wikipedia.org/wiki/Micronoctuidae"}, +{388,"http://en.wikipedia.org/wiki/Mike_Dunleavy,_Jr."}, +{426,"http://en.wikipedia.org/wiki/Milo%C5%A1_Vujani%C4%87"}, +{364,"http://en.wikipedia.org/wiki/Milwaukee_Bucks"}, +{404,"http://en.wikipedia.org/wiki/Ministries_of_Turkey"}, +{596,"http://en.wikipedia.org/wiki/Ministry_of_Education_and_Training_(Vietnam)"}, +{532,"http://en.wikipedia.org/wiki/Ministry_of_Foreign_Affairs_(Turkey)"}, +{388,"http://en.wikipedia.org/wiki/Miroslav_Raduljica"}, +{412,"http://en.wikipedia.org/wiki/Mladen_%C5%A0ekularac"}, +{300,"http://en.wikipedia.org/wiki/Monarch"}, +{276,"http://en.wikipedia.org/wiki/Moth"}, +{340,"http://en.wikipedia.org/wiki/Mountain_Dew"}, +{436,"http://en.wikipedia.org/wiki/Mouse_Genome_Informatics"}, +{340,"http://en.wikipedia.org/wiki/Municipality"}, +{452,"http://en.wikipedia.org/wiki/Mustafa_Kemal_Atat%C3%BCrk"}, +{268,"http://en.wikipedia.org/wiki/NBA"}, +{396,"http://en.wikipedia.org/wiki/NBA_All-Rookie_Team"}, +{380,"http://en.wikipedia.org/wiki/NBA_All-Star_Game"}, +{292,"http://en.wikipedia.org/wiki/Nahiye"}, +{472,"http://en.wikipedia.org/wiki/Nam_%C4%90%E1%BB%8Bnh_Province"}, +{340,"http://en.wikipedia.org/wiki/Nate_Wolters"}, +{540,"http://en.wikipedia.org/wiki/National_Basketball_Association_draft"}, +{516,"http://en.wikipedia.org/wiki/National_Security_Council_(Turkey)"}, +{404,"http://en.wikipedia.org/wiki/National_sovereignty"}, +{348,"http://en.wikipedia.org/wiki/Neme%C5%A1any"}, +{314,"http://en.wikipedia.org/wiki/Nen%C3%AA"}, +{378,"http://en.wikipedia.org/wiki/Nenad_Krsti%C4%87"}, +{420,"http://en.wikipedia.org/wiki/New_Orleans,_Louisiana"}, +{364,"http://en.wikipedia.org/wiki/New_York_Knicks"}, +{436,"http://en.wikipedia.org/wiki/Ngh%E1%BB%87_An_Province"}, +{484,"http://en.wikipedia.org/wiki/Nguyen_Thuong_Hien_High_School"}, +{460,"http://en.wikipedia.org/wiki/Ni%C5%BEn%C3%A9_Repa%C5%A1e"}, +{348,"http://en.wikipedia.org/wiki/Nick_Van_Exel"}, +{404,"http://en.wikipedia.org/wiki/Nikoloz_Tskitishvili"}, +{324,"http://en.wikipedia.org/wiki/Noctuoidea"}, +{378,"http://en.wikipedia.org/wiki/O%C4%BE%C5%A1avica"}, +{324,"http://en.wikipedia.org/wiki/O._J._Mayo"}, +{340,"http://en.wikipedia.org/wiki/Open_Library"}, +{316,"http://en.wikipedia.org/wiki/Ordzovany"}, +{412,"http://en.wikipedia.org/wiki/Oriel_College,_Oxford"}, +{332,"http://en.wikipedia.org/wiki/Otto_Porter"}, +{356,"http://en.wikipedia.org/wiki/Ottoman_Empire"}, +{364,"http://en.wikipedia.org/wiki/Ottoman_dynasty"}, +{372,"http://en.wikipedia.org/wiki/Ottoman_language"}, +{620,"http://en.wikipedia.org/wiki/Outline_of_political_science#Politics_by_region"}, +{500,"http://en.wikipedia.org/wiki/Parliament_of_the_United_Kingdom"}, +{332,"http://en.wikipedia.org/wiki/Pat_Garrity"}, +{348,"http://en.wikipedia.org/wiki/Patrick_Ewing"}, +{340,"http://en.wikipedia.org/wiki/Pav%C4%BEany"}, +{402,"http://en.wikipedia.org/wiki/Peja_Stojakovi%C4%87"}, +{388,"http://en.wikipedia.org/wiki/Perils_of_the_Wild"}, +{332,"http://en.wikipedia.org/wiki/Peter_Fehse"}, +{476,"http://en.wikipedia.org/wiki/Ph%C3%BA_Th%E1%BB%8D_Province"}, +{452,"http://en.wikipedia.org/wiki/Ph%C3%BA_Y%C3%AAn_Province"}, +{340,"http://en.wikipedia.org/wiki/Phoenix_Suns"}, +{380,"http://en.wikipedia.org/wiki/Pittsfield,_Maine"}, +{356,"http://en.wikipedia.org/wiki/Po%C4%BEanovce"}, +{388,"http://en.wikipedia.org/wiki/Politics_of_Turkey"}, +{524,"http://en.wikipedia.org/wiki/Politics_of_Turkey#Executive_branch"}, +{540,"http://en.wikipedia.org/wiki/Politics_of_Turkey#Legislative_branch"}, +{372,"http://en.wikipedia.org/wiki/Pongr%C3%A1covce"}, +{324,"http://en.wikipedia.org/wiki/Population"}, +{372,"http://en.wikipedia.org/wiki/Portal:Biography"}, +{364,"http://en.wikipedia.org/wiki/Portal:Contents"}, +{412,"http://en.wikipedia.org/wiki/Portal:Current_events"}, +{428,"http://en.wikipedia.org/wiki/Portal:Featured_content"}, +{364,"http://en.wikipedia.org/wiki/Portal:Politics"}, +{348,"http://en.wikipedia.org/wiki/Portal:Turkey"}, +{388,"http://en.wikipedia.org/wiki/Pre%C5%A1ov_Region"}, +{396,"http://en.wikipedia.org/wiki/President_of_Turkey"}, +{436,"http://en.wikipedia.org/wiki/Prime_Minister_of_Turkey"}, +{380,"http://en.wikipedia.org/wiki/Project_Gutenberg"}, +{380,"http://en.wikipedia.org/wiki/Protein_Data_Bank"}, +{292,"http://en.wikipedia.org/wiki/PubMed"}, +{356,"http://en.wikipedia.org/wiki/PubMed_Central"}, +{380,"http://en.wikipedia.org/wiki/PubMed_Identifier"}, +{372,"http://en.wikipedia.org/wiki/Public_relations"}, +{284,"http://en.wikipedia.org/wiki/Qadaa"}, +{460,"http://en.wikipedia.org/wiki/Qu%E1%BA%A3ng_Ninh_Province"}, +{340,"http://en.wikipedia.org/wiki/Quinton_Ross"}, +{636,"http://en.wikipedia.org/wiki/Quoc_Hoc_%E2%80%93_Hue_High_School_for_the_Gifted"}, +{340,"http://en.wikipedia.org/wiki/Qyntel_Woods"}, +{380,"http://en.wikipedia.org/wiki/Racine,_Wisconsin"}, +{428,"http://en.wikipedia.org/wiki/Racine_Park_High_School"}, +{324,"http://en.wikipedia.org/wiki/Randy_Foye"}, +{348,"http://en.wikipedia.org/wiki/Randy_Holcomb"}, +{348,"http://en.wikipedia.org/wiki/Rasual_Butler"}, +{316,"http://en.wikipedia.org/wiki/Ray_Allen"}, +{404,"http://en.wikipedia.org/wiki/Rebound_(basketball)"}, +{444,"http://en.wikipedia.org/wiki/Recep_Tayyip_Erdo%C4%9Fan"}, +{556,"http://en.wikipedia.org/wiki/Reggie_Williams_(basketball,_born_1964)"}, +{308,"http://en.wikipedia.org/wiki/Republic"}, +{388,"http://en.wikipedia.org/wiki/Republic_of_Turkey"}, +{476,"http://en.wikipedia.org/wiki/Richard_Hamilton_(basketball)"}, +{348,"http://en.wikipedia.org/wiki/Rick_Carlisle"}, +{372,"http://en.wikipedia.org/wiki/Robert_Archibald"}, +{604,"http://en.wikipedia.org/wiki/Robert_Haldane-Duncan,_3rd_Earl_of_Camperdown"}, +{364,"http://en.wikipedia.org/wiki/Robinson_Crusoe"}, +{340,"http://en.wikipedia.org/wiki/Rod_Grizzard"}, +{380,"http://en.wikipedia.org/wiki/Rodrigue_Beaubois"}, +{372,"http://en.wikipedia.org/wiki/Roger_Mason,_Jr."}, +{348,"http://en.wikipedia.org/wiki/Ronald_Murray"}, +{348,"http://en.wikipedia.org/wiki/Ryan_Humphrey"}, +{364,"http://en.wikipedia.org/wiki/Sam_Clancy,_Jr."}, +{436,"http://en.wikipedia.org/wiki/Samuel_Trehawke_Kekewich"}, +{380,"http://en.wikipedia.org/wiki/San_Antonio_Spurs"}, +{460,"http://en.wikipedia.org/wiki/Scott_Williams_(basketball)"}, +{404,"http://en.wikipedia.org/wiki/Secularism_in_Turkey"}, +{348,"http://en.wikipedia.org/wiki/Sephardi_Jews"}, +{388,"http://en.wikipedia.org/wiki/Shaquille_O%27Neal"}, +{340,"http://en.wikipedia.org/wiki/Shawn_Marion"}, +{548,"http://en.wikipedia.org/wiki/Sir_Manasseh_Masseh_Lopes,_1st_Baronet"}, +{476,"http://en.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet"}, +{484,"http://en.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet#"}, +{572,"http://en.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet#cite_note-1"}, +{564,"http://en.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet#cite_ref-1"}, +{588,"http://en.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet#mw-navigation"}, +{548,"http://en.wikipedia.org/wiki/Sir_Massey_Lopes,_3rd_Baronet#p-search"}, +{468,"http://en.wikipedia.org/wiki/Sir_Ralph_Lopes,_2nd_Baronet"}, +{308,"http://en.wikipedia.org/wiki/Slovakia"}, +{348,"http://en.wikipedia.org/wiki/Small_forward"}, +{564,"http://en.wikipedia.org/wiki/South_Devon_(UK_Parliament_constituency)"}, +{444,"http://en.wikipedia.org/wiki/South_Melbourne,_Victoria"}, +{332,"http://en.wikipedia.org/wiki/Sovereignty"}, +{412,"http://en.wikipedia.org/wiki/Space_Family_Robinson"}, +{463,"http://en.wikipedia.org/wiki/Special:BookSources/0091354609"}, +{356,"http://en.wikipedia.org/wiki/Special:Random"}, +{412,"http://en.wikipedia.org/wiki/Special:RecentChanges"}, +{572,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Ambrose_Dyson"}, +{564,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Caron_Butler"}, +{548,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/DDT_(gene)"}, +{604,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Johann_David_Wyss"}, +{540,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Lady_Anne"}, +{700,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Sir_Massey_Lopes,_3rd_Baronet"}, +{516,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Tumula"}, +{688,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Turkish_Constitution_of_1921"}, +{764,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Vietnam_University_Admission_Rankings"}, +{652,"http://en.wikipedia.org/wiki/Special:RecentChangesLinked/Vy%C5%A1n%C3%BD_Slavkov"}, +{404,"http://en.wikipedia.org/wiki/Special:SpecialPages"}, +{524,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Ambrose_Dyson"}, +{516,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Caron_Butler"}, +{500,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/DDT_(gene)"}, +{556,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Johann_David_Wyss"}, +{492,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Lady_Anne"}, +{652,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Sir_Massey_Lopes,_3rd_Baronet"}, +{468,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Tumula"}, +{640,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Turkish_Constitution_of_1921"}, +{716,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Vietnam_University_Admission_Rankings"}, +{604,"http://en.wikipedia.org/wiki/Special:WhatLinksHere/Vy%C5%A1n%C3%BD_Slavkov"}, +{460,"http://en.wikipedia.org/wiki/Spi%C5%A1sk%C3%A9_Podhradie"}, +{484,"http://en.wikipedia.org/wiki/Spi%C5%A1sk%C3%BD_%C5%A0tvrtok"}, +{428,"http://en.wikipedia.org/wiki/Spi%C5%A1sk%C3%BD_Hrhov"}, +{388,"http://en.wikipedia.org/wiki/Steal_(basketball)"}, +{332,"http://en.wikipedia.org/wiki/Steve_Logan"}, +{404,"http://en.wikipedia.org/wiki/Stranded_(2002_film)"}, +{492,"http://en.wikipedia.org/wiki/Studenec_(Levo%C4%8Da_District)"}, +{292,"http://en.wikipedia.org/wiki/Sultan"}, +{524,"http://en.wikipedia.org/wiki/Supreme_Electoral_Council_of_Turkey"}, +{444,"http://en.wikipedia.org/wiki/Swiss_Family_Guy_Robinson"}, +{508,"http://en.wikipedia.org/wiki/Swiss_Family_Robinson_(1940_film)"}, +{508,"http://en.wikipedia.org/wiki/Swiss_Family_Robinson_(1960_film)"}, +{548,"http://en.wikipedia.org/wiki/Swiss_Family_Robinson_(1974_TV_series)"}, +{332,"http://en.wikipedia.org/wiki/Switzerland"}, +{292,"http://en.wikipedia.org/wiki/Sydney"}, +{324,"http://en.wikipedia.org/wiki/Tactusinae"}, +{388,"http://en.wikipedia.org/wiki/Talk:Ambrose_Dyson"}, +{380,"http://en.wikipedia.org/wiki/Talk:Caron_Butler"}, +{364,"http://en.wikipedia.org/wiki/Talk:DDT_(gene)"}, +{420,"http://en.wikipedia.org/wiki/Talk:Johann_David_Wyss"}, +{516,"http://en.wikipedia.org/wiki/Talk:Sir_Massey_Lopes,_3rd_Baronet"}, +{332,"http://en.wikipedia.org/wiki/Talk:Tumula"}, +{504,"http://en.wikipedia.org/wiki/Talk:Turkish_Constitution_of_1921"}, +{580,"http://en.wikipedia.org/wiki/Talk:Vietnam_University_Admission_Rankings"}, +{468,"http://en.wikipedia.org/wiki/Talk:Vy%C5%A1n%C3%BD_Slavkov"}, +{324,"http://en.wikipedia.org/wiki/Tamar_Slay"}, +{364,"http://en.wikipedia.org/wiki/Tayshaun_Prince"}, +{428,"http://en.wikipedia.org/wiki/Template:2002_NBA_Draft"}, +{828,"http://en.wikipedia.org/wiki/Template:Big_East_Conference_Men%27s_Basketball_Player_of_the_Year_navbox"}, +{436,"http://en.wikipedia.org/wiki/Template:Cartoonist-stub"}, +{436,"http://en.wikipedia.org/wiki/Template:Citation_needed"}, +{492,"http://en.wikipedia.org/wiki/Template:Constitution_of_Turkey"}, +{672,"http://en.wikipedia.org/wiki/Template:Dallas_Mavericks_2010%E2%80%9311_NBA_champions"}, +{412,"http://en.wikipedia.org/wiki/Template:Gene-22-stub"}, +{476,"http://en.wikipedia.org/wiki/Template:Levo%C4%8Da_District"}, +{556,"http://en.wikipedia.org/wiki/Template:Milwaukee_Bucks_current_roster"}, +{436,"http://en.wikipedia.org/wiki/Template:Noctuoidea-stub"}, +{371,"http://en.wikipedia.org/wiki/Template:PBB/1652"}, +{404,"http://en.wikipedia.org/wiki/Template:PDB_Gallery"}, +{460,"http://en.wikipedia.org/wiki/Template:Politics_of_Turkey"}, +{476,"http://en.wikipedia.org/wiki/Template:Pre%C5%A1ov-geo-stub"}, +{500,"http://en.wikipedia.org/wiki/Template:Switzerland-writer-stub"}, +{516,"http://en.wikipedia.org/wiki/Template:The_Swiss_Family_Robinson"}, +{396,"http://en.wikipedia.org/wiki/Template:Translated"}, +{468,"http://en.wikipedia.org/wiki/Template_talk:2002_NBA_Draft"}, +{868,"http://en.wikipedia.org/wiki/Template_talk:Big_East_Conference_Men%27s_Basketball_Player_of_the_Year_navbox"}, +{476,"http://en.wikipedia.org/wiki/Template_talk:Cartoonist-stub"}, +{532,"http://en.wikipedia.org/wiki/Template_talk:Constitution_of_Turkey"}, +{712,"http://en.wikipedia.org/wiki/Template_talk:Dallas_Mavericks_2010%E2%80%9311_NBA_champions"}, +{452,"http://en.wikipedia.org/wiki/Template_talk:Gene-22-stub"}, +{516,"http://en.wikipedia.org/wiki/Template_talk:Levo%C4%8Da_District"}, +{596,"http://en.wikipedia.org/wiki/Template_talk:Milwaukee_Bucks_current_roster"}, +{476,"http://en.wikipedia.org/wiki/Template_talk:Noctuoidea-stub"}, +{444,"http://en.wikipedia.org/wiki/Template_talk:PDB_Gallery"}, +{500,"http://en.wikipedia.org/wiki/Template_talk:Politics_of_Turkey"}, +{516,"http://en.wikipedia.org/wiki/Template_talk:Pre%C5%A1ov-geo-stub"}, +{540,"http://en.wikipedia.org/wiki/Template_talk:Switzerland-writer-stub"}, +{340,"http://en.wikipedia.org/wiki/Terry_Dehere"}, +{340,"http://en.wikipedia.org/wiki/Terry_Stotts"}, +{468,"http://en.wikipedia.org/wiki/Th%C3%A1i_B%C3%ACnh_Province"}, +{660,"http://en.wikipedia.org/wiki/Th%E1%BB%ABa_Thi%C3%AAn%E2%80%93Hu%E1%BA%BF_Province"}, +{356,"http://en.wikipedia.org/wiki/Thanh_H%C3%B3a"}, +{428,"http://en.wikipedia.org/wiki/Thanh_H%C3%B3a_Province"}, +{340,"http://en.wikipedia.org/wiki/The_Bulletin"}, +{444,"http://en.wikipedia.org/wiki/The_Castaways_of_the_Flag"}, +{388,"http://en.wikipedia.org/wiki/The_London_Gazette"}, +{444,"http://en.wikipedia.org/wiki/The_Swiss_Family_Robinson"}, +{700,"http://en.wikipedia.org/wiki/The_Swiss_Family_Robinson:_Flone_of_the_Mysterious_Island"}, +{580,"http://en.wikipedia.org/wiki/The_Swiss_Family_Robinson_(1975_TV_series)"}, +{500,"http://en.wikipedia.org/wiki/Thomas_Brassey,_1st_Earl_Brassey"}, +{420,"http://en.wikipedia.org/wiki/Three-point_field_goal"}, +{340,"http://en.wikipedia.org/wiki/Tim_Grgurich"}, +{420,"http://en.wikipedia.org/wiki/Tim_James_(basketball)"}, +{332,"http://en.wikipedia.org/wiki/Tito_Maddox"}, +{324,"http://en.wikipedia.org/wiki/Tom_Durkin"}, +{300,"http://en.wikipedia.org/wiki/Torysky"}, +{452,"http://en.wikipedia.org/wiki/Tran_Dai_Nghia_High_School"}, +{388,"http://en.wikipedia.org/wiki/Treaty_of_Lausanne"}, +{412,"http://en.wikipedia.org/wiki/Treaty_of_S%C3%A8vres"}, +{316,"http://en.wikipedia.org/wiki/Troy_Bell"}, +{332,"http://en.wikipedia.org/wiki/Troy_Murphy"}, +{292,"http://en.wikipedia.org/wiki/Tumula"}, +{300,"http://en.wikipedia.org/wiki/Tumula#"}, +{404,"http://en.wikipedia.org/wiki/Tumula#mw-navigation"}, +{364,"http://en.wikipedia.org/wiki/Tumula#p-search"}, +{388,"http://en.wikipedia.org/wiki/Tumula_flavicollis"}, +{292,"http://en.wikipedia.org/wiki/Turkey"}, +{660,"http://en.wikipedia.org/wiki/Turkey%27s_membership_of_international_organizations"}, +{404,"http://en.wikipedia.org/wiki/Turkish_Armed_Forces"}, +{464,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921"}, +{476,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#"}, +{556,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#Background"}, +{588,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#External_links"}, +{540,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#Overview"}, +{556,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#References"}, +{644,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#Text_.28as_enacted.29"}, +{540,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#Timeline"}, +{564,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#cite_note-1"}, +{556,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#cite_ref-1"}, +{580,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#mw-navigation"}, +{540,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1921#p-search"}, +{464,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1924"}, +{464,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1961"}, +{464,"http://en.wikipedia.org/wiki/Turkish_Constitution_of_1982"}, +{436,"http://en.wikipedia.org/wiki/Turkish_Council_of_State"}, +{436,"http://en.wikipedia.org/wiki/Turkish_Independence_War"}, +{460,"http://en.wikipedia.org/wiki/Turkish_War_of_Independence"}, +{480,"http://en.wikipedia.org/wiki/Turkish_general_election,_2011"}, +{372,"http://en.wikipedia.org/wiki/Turkish_language"}, +{472,"http://en.wikipedia.org/wiki/Turkish_local_elections,_2009"}, +{520,"http://en.wikipedia.org/wiki/Turkish_presidential_election,_2007"}, +{356,"http://en.wikipedia.org/wiki/Tyson_Chandler"}, +{420,"http://en.wikipedia.org/wiki/USS_Lady_Anne_(SP-154)"}, +{324,"http://en.wikipedia.org/wiki/Ulo%C5%BEa"}, +{300,"http://en.wikipedia.org/wiki/UniProt"}, +{348,"http://en.wikipedia.org/wiki/United_States"}, +{548,"http://en.wikipedia.org/wiki/United_States_national_basketball_team"}, +{444,"http://en.wikipedia.org/wiki/University_of_Connecticut"}, +{468,"http://en.wikipedia.org/wiki/V%C4%A9nh_Ph%C3%BAc_Province"}, +{567,"http://en.wikipedia.org/wiki/Vanity_Fair_(British_magazine_1868-1914)"}, +{396,"http://en.wikipedia.org/wiki/Viacheslav_Kravtsov"}, +{540,"http://en.wikipedia.org/wiki/Vietnam_University_Admission_Rankings"}, +{548,"http://en.wikipedia.org/wiki/Vietnam_University_Admission_Rankings#"}, +{636,"http://en.wikipedia.org/wiki/Vietnam_University_Admission_Rankings#cite_note-1"}, +{628,"http://en.wikipedia.org/wiki/Vietnam_University_Admission_Rankings#cite_ref-1"}, +{652,"http://en.wikipedia.org/wiki/Vietnam_University_Admission_Rankings#mw-navigation"}, +{612,"http://en.wikipedia.org/wiki/Vietnam_University_Admission_Rankings#p-search"}, +{340,"http://en.wikipedia.org/wiki/Vil%C3%A2yet"}, +{300,"http://en.wikipedia.org/wiki/Village"}, +{380,"http://en.wikipedia.org/wiki/Vincent_Yarbrough"}, +{532,"http://en.wikipedia.org/wiki/Virtual_International_Authority_File"}, +{460,"http://en.wikipedia.org/wiki/Vy%C5%A1n%C3%A9_Repa%C5%A1e"}, +{428,"http://en.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{436,"http://en.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov#"}, +{540,"http://en.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov#mw-navigation"}, +{500,"http://en.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov#p-search"}, +{444,"http://en.wikipedia.org/wiki/Walter_Berry_(basketball)"}, +{372,"http://en.wikipedia.org/wiki/Washington,_D.C."}, +{460,"http://en.wikipedia.org/wiki/Washington_Park_High_School"}, +{388,"http://en.wikipedia.org/wiki/Washington_Wizards"}, +{460,"http://en.wikipedia.org/wiki/Wesley_Johnson_(basketball)"}, +{540,"http://en.wikipedia.org/wiki/Westbury_(UK_Parliament_constituency)"}, +{364,"http://en.wikipedia.org/wiki/Wikipedia:About"}, +{444,"http://en.wikipedia.org/wiki/Wikipedia:Citation_needed"}, +{436,"http://en.wikipedia.org/wiki/Wikipedia:Citing_sources"}, +{452,"http://en.wikipedia.org/wiki/Wikipedia:Community_portal"}, +{404,"http://en.wikipedia.org/wiki/Wikipedia:Contact_us"}, +{516,"http://en.wikipedia.org/wiki/Wikipedia:Copying_within_Wikipedia"}, +{468,"http://en.wikipedia.org/wiki/Wikipedia:File_Upload_Wizard"}, +{468,"http://en.wikipedia.org/wiki/Wikipedia:General_disclaimer"}, +{548,"http://en.wikipedia.org/wiki/Wikipedia:Identifying_reliable_sources"}, +{362,"http://en.wikipedia.org/wiki/Wikipedia:NOTRS"}, +{404,"http://en.wikipedia.org/wiki/Wikipedia:Persondata"}, +{356,"http://en.wikipedia.org/wiki/Wikipedia:Stub"}, +{868,"http://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License"}, +{412,"http://en.wikipedia.org/wiki/Wikipedia:Translation"}, +{372,"http://en.wikipedia.org/wiki/Wikipedia:V#SELF"}, +{580,"http://en.wikipedia.org/wiki/Wikipedia:Verifiability#Burden_of_evidence"}, +{324,"http://en.wikipedia.org/wiki/Will_Dyson"}, +{388,"http://en.wikipedia.org/wiki/Winchester_College"}, +{316,"http://en.wikipedia.org/wiki/Wisconsin"}, +{332,"http://en.wikipedia.org/wiki/World_War_I"}, +{292,"http://en.wikipedia.org/wiki/Yahoo!"}, +{308,"http://en.wikipedia.org/wiki/Yao_Ming"}, +{348,"http://en.wikipedia.org/wiki/Zaza_Pachulia"}, +{556,"http://en.wikisource.org/wiki/Constitution_of_the_Republic_of_Turkey"}, +{428,"http://eo.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{340,"http://es.wikipedia.org/wiki/Caron_Butler"}, +{380,"http://es.wikipedia.org/wiki/Johann_David_Wyss"}, +{228,"http://everything.yahoo.com"}, +{236,"http://everything.yahoo.com/"}, +{420,"http://feedback.yahoo.com/forums/206380-us-homepage"}, +{204,"http://finance.yahoo.com"}, +{212,"http://finance.yahoo.com/"}, +{602,"http://finance.yahoo.com/news/brazil-looks-break-us-centric-040621384.html"}, +{554,"http://finance.yahoo.com/news/did-ted-cruz-just-force-211204954.html"}, +{642,"http://finance.yahoo.com/news/theyve-turned-over-costa-concordia-102731647.html"}, +{284,"http://finance.yahoo.com/q?s=^IXIC"}, +{578,"http://finance.yahoo.com/video/winning-lottery-beat-odds-193258229.html"}, +{148,"http://flickr.com"}, +{404,"http://flss.edu.vn/Home.asp?param=news&NewsID=147"}, +{980,"http://football.fantasysports.yahoo.com/?ovchn=YAH&ovcpn=Front+Page&ovcrn=Front+page+P+Link+Nav+button&ovrfd=YAH&ovtac=AD"}, +{340,"http://fr.wikipedia.org/wiki/Caron_Butler"}, +{380,"http://fr.wikipedia.org/wiki/Johann_David_Wyss"}, +{428,"http://fr.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{196,"http://games.yahoo.com/"}, +{697,"http://genome.ucsc.edu/cgi-bin/hgTracks?org=Human&db=hg19&position=chr22:24313554-24322660"}, +{689,"http://genome.ucsc.edu/cgi-bin/hgTracks?org=Mouse&db=mm9&position=chr10:75771230-75773414"}, +{340,"http://gl.wikipedia.org/wiki/Caron_Butler"}, +{196,"http://green.yahoo.com/"}, +{204,"http://groups.yahoo.com/"}, +{687,"http://hangtime.blogs.nba.com/2011/01/04/caron-butler-out-for-season/?ls=iref:nbahpt2"}, +{476,"http://hansard.millbanksystems.com/people/sir-massey-lopes"}, +{618,"http://he.wikipedia.org/wiki/%D7%A7%D7%90%D7%A8%D7%95%D7%9F_%D7%91%D7%90%D7%98%D7%9C%D7%A8"}, +{196,"http://health.yahoo.net"}, +{636,"http://health.yahoo.net/articles/weight-loss/why-obese-people-cant-lose-weight"}, +{653,"http://help.yahoo.com/kb/index?page=content&y=PROD_FRONT&locale=en_US&id=SLN14553"}, +{372,"http://help.yahoo.com/l/us/yahoo/helpcentral/"}, +{268,"http://homes.yahoo.com/own-rent/"}, +{340,"http://hr.wikipedia.org/wiki/Caron_Butler"}, +{412,"http://hu.wikipedia.org/wiki/Fels%C5%91szal%C3%B3k"}, +{180,"http://info.yahoo.com"}, +{188,"http://info.yahoo.com/"}, +{396,"http://info.yahoo.com/legal/us/yahoo/utos/terms/"}, +{396,"http://info.yahoo.com/privacy/us/yahoo/homepage/"}, +{452,"http://info.yahoo.com/privacy/us/yahoo/relevantads.html"}, +{340,"http://it.wikipedia.org/wiki/Caron_Butler"}, +{428,"http://it.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{651,"http://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AD%E3%83%B3%E3%83%BB%E3%83%90%E3%83%88%E3%83%A9%E3%83%BC"}, +{898,"http://ja.wikipedia.org/wiki/%E3%83%A8%E3%83%8F%E3%83%B3%E3%83%BB%E3%83%80%E3%83%93%E3%83%83%E3%83%88%E3%83%BB%E3%82%A6%E3%82%A3%E3%83%BC%E3%82%B9"}, +{564,"http://jobsearch.monster.com/search/?cy=us&WT.mc_n=yta_trough_jsrtest"}, +{596,"http://librivox.org/newcatalog/search.php?title=&author=Johann+David+Wyss"}, +{356,"http://lv.wikipedia.org/wiki/Kerons_Batlers"}, +{252,"http://mail.yahoo.com?.intl=us"}, +{188,"http://maps.yahoo.com/"}, +{220,"http://messenger.yahoo.com"}, +{196,"http://movies.yahoo.com"}, +{522,"http://movies.yahoo.com/video/short-game-crushing-224038083.html"}, +{428,"http://ms.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{188,"http://music.yahoo.com"}, +{276,"http://my.yahoo.com/?fr=yfp-t-403"}, +{634,"http://myespn.go.com/blogs/truehoop/0-24-118/Caron-Butler-in-the-Basement.html"}, +{188,"http://news.yahoo.com/"}, +{618,"http://news.yahoo.com/amazing-roll-cloud-tumbles-over-dc-area-161409111.html"}, +{994,"http://news.yahoo.com/blogs/trending-now/family-sells-home--goes-on-epic-yearlong-trip-to-all-50-states-185712913.html?vp=1"}, +{388,"http://news.yahoo.com/comics/dilbert-slideshow/"}, +{746,"http://news.yahoo.com/cost-cutting-may-have-played-role-in-navy-yard-shooting-134106229.html"}, +{682,"http://news.yahoo.com/giant-underground-blob-magma-puzzles-scientists-210726200.html"}, +{746,"http://news.yahoo.com/lightbox/dilbert-slideshow/20130523-dt130523-gif-photo-050423497.html"}, +{516,"http://news.yahoo.com/photos/costa-concordia-salvage-slideshow/"}, +{599,"http://news.yahoo.com/photos/turtle-rescue-in-israel-1379421810-slideshow/"}, +{666,"http://news.yahoo.com/put-business-trauma-doctor-pleads-u-navy-yard-181522657.html"}, +{698,"http://news.yahoo.com/touting-obamacare-us-says-millions-could-pay-less-212243340.html"}, +{578,"http://news.yahoo.com/video/old-soda-bottles-giving-life-001700872.html"}, +{380,"http://nl.wikipedia.org/wiki/Johann_David_Wyss"}, +{428,"http://nl.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{380,"http://no.wikipedia.org/wiki/Johann_David_Wyss"}, +{180,"http://omg.yahoo.com/"}, +{650,"http://omg.yahoo.com/blogs/celeb-news/brad-pitt-finally-makes-cut-223549188.html"}, +{794,"http://omg.yahoo.com/blogs/celeb-news/fashion-faceoff-miley-cyrus-vs-rachel-mcadams-190957403.html"}, +{882,"http://omg.yahoo.com/blogs/celeb-news/justin-theroux-reveals-one-thing-jennifer-aniston-wouldn-113635271.html"}, +{882,"http://omg.yahoo.com/news/courteney-cox-david-arquette-selling-beverly-hills-mansion-184500328-us-weekly.html"}, +{232,"http://omim.org/entry/602750"}, +{3387,"http://open.login.yahoo.net/openid/yrp/hr_signin?.intl=us&idp=facebook&ts=1379461518&rpcrumb=&.src=home&appid=90376669494&spid=b9ed13cc-ddec-11de-9c83-001b784d35e1&perms=email,user_birthday,user_education_history,user_likes,user_location,user_relationships,user_subscriptions,user_work_history,friends_birthday,friends_education_history,friends_likes,friends_location,friends_work_history&.done=http%3A%2F%2Fwww.yahoo.com%2F"}, +{320,"http://openlibrary.org/authors/OL342629A"}, +{340,"http://pl.wikipedia.org/wiki/Caron_Butler"}, +{380,"http://pl.wikipedia.org/wiki/Johann_David_Wyss"}, +{428,"http://pl.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{855,"http://probasketballtalk.nbcsports.com/2010/07/21/caron-butler-used-to-work-at-a-burger-king-now-owns-six/"}, +{340,"http://pt.wikipedia.org/wiki/Caron_Butler"}, +{659,"http://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%82%D0%BB%D0%B5%D1%80,_%D0%9A%D1%8D%D1%80%D0%BE%D0%BD"}, +{917,"http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D0%B8%D1%82%D1%83%D1%86%D0%B8%D1%8F_%D0%A2%D1%83%D1%80%D1%86%D0%B8%D0%B8_(1921)"}, +{204,"http://screen.yahoo.com/"}, +{453,"http://screen.yahoo.com/11-old-boy-made-9-134626064.html"}, +{738,"http://screen.yahoo.com/snl-women-skits/girl-wish-hadnt-started-conversation-000000658.html"}, +{204,"http://search.yahoo.com/"}, +{244,"http://search.yahoo.com/local"}, +{741,"http://search.yahoo.com/search?cs=bz&p=Biblical-era%20town&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{765,"http://search.yahoo.com/search?cs=bz&p=Green%20River%20Killer&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{733,"http://search.yahoo.com/search?cs=bz&p=Hostile%20takeover&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{741,"http://search.yahoo.com/search?cs=bz&p=Jennifer%20Lopez%20&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{701,"http://search.yahoo.com/search?cs=bz&p=Jessa%20Duggar&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{717,"http://search.yahoo.com/search?cs=bz&p=Kim%20Zolciak%20&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{717,"http://search.yahoo.com/search?cs=bz&p=LSU%20fraternity&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{741,"http://search.yahoo.com/search?cs=bz&p=Linda%20Ronstadt%20&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{749,"http://search.yahoo.com/search?cs=bz&p=Star%20Trek%20NSA%20&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{781,"http://search.yahoo.com/search?cs=bz&p=Walking%20Dead%20spinoff&fr=fp-tts-900&fr2=ps&woeid=23424856"}, +{188,"http://shine.yahoo.com"}, +{196,"http://shine.yahoo.com/"}, +{276,"http://shine.yahoo.com/horoscope/"}, +{548,"http://shine.yahoo.com/horoscope/virgo/extended-daily-20130917.html"}, +{548,"http://shine.yahoo.com/horoscope/virgo/overview-daily-20130917.html"}, +{754,"http://shine.yahoo.com/shine-food/5-things-didnt-know-could-pillsbury-biscuits-205500571.html"}, +{730,"http://shine.yahoo.com/shine-food/fabios-ultimate-pulled-pork-sandwich-011700797.html?vp=1"}, +{220,"http://shopping.yahoo.com/"}, +{412,"http://simple.wikipedia.org/wiki/Johann_David_Wyss"}, +{428,"http://sk.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{436,"http://smallbusiness.yahoo.com/?s_fptrough=ysb_acq_fp"}, +{402,"http://sports.espn.go.com/nba/news/story?id=3290089"}, +{400,"http://sports.espn.go.com/nba/recap?gameId=270117027"}, +{400,"http://sports.espn.go.com/nba/recap?gameId=280313027"}, +{196,"http://sports.yahoo.com"}, +{204,"http://sports.yahoo.com/"}, +{911,"http://sports.yahoo.com/blogs/mlb-big-league-stew/fan-dashes-onto-field-during-rays-game-only-192151790--mlb.html"}, +{991,"http://sports.yahoo.com/blogs/nfl-shutdown-corner/does-andy-reid-still-wish-philadelphia-jamaal-charles-180705907--nfl.html"}, +{260,"http://sports.yahoo.com/fantasy"}, +{228,"http://sports.yahoo.com/mlb"}, +{376,"http://sports.yahoo.com/mlb/preview?gid=330917104"}, +{360,"http://sports.yahoo.com/mlb/recap?gid=330917220"}, +{308,"http://sports.yahoo.com/mlb/teams/atl"}, +{939,"http://sports.yahoo.com/nba/blog/ball_dont_lie/post/More-on-Caron-Butler-s-extreme-Mountain-Dew-addi?urn=nba%2C198240"}, +{332,"http://sports.yahoo.com/nba/players/3608"}, +{647,"http://sports.yahoo.com/news/team-report-san-francisco-49ers-211200051--nfl.html"}, +{228,"http://sports.yahoo.com/nfl"}, +{383,"http://sports.yahoo.com/nfl/preview?gid=20130919021"}, +{367,"http://sports.yahoo.com/nfl/recap?gid=20130916004"}, +{308,"http://sports.yahoo.com/nfl/teams/cin"}, +{228,"http://sports.yahoo.com/nhl"}, +{308,"http://sports.yahoo.com/nhl/teams/was"}, +{684,"http://sr.wikipedia.org/wiki/%D0%92%D0%B8%D1%88%D0%BD%D0%B8_%D0%A1%D0%BB%D0%B0%D0%B2%D0%BA%D0%BE%D0%B2"}, +{832,"http://ta.wikipedia.org/wiki/%E0%AE%95%E0%AE%B0%E0%AE%BE%E0%AE%A9%E0%AF%8D_%E0%AE%AA%E0%AE%9F%E0%AF%8D%E0%AE%B2%E0%AE%B0%E0%AF%8D"}, +{931,"http://th.wikipedia.org/wiki/%E0%B9%81%E0%B8%84%E0%B8%A3%E0%B8%AD%E0%B8%99_%E0%B8%9A%E0%B8%B1%E0%B8%95%E0%B9%80%E0%B8%A5%E0%B8%AD%E0%B8%A3%E0%B9%8C"}, +{818,"http://thptbinhxuyen.edu.vn/vp/Top-200-truong-THPT-co-diem-thi-dai-hoc-cao-nhat-2011-t11736-7938.html"}, +{972,"http://tools.wmflabs.org/geohack/geohack.php?pagename=Vy%C5%A1n%C3%BD_Slavkov¶ms=49_04_N_20_52_E_region:SK_type:city"}, +{340,"http://tr.wikipedia.org/wiki/Caron_Butler"}, +{604,"http://tr.wikipedia.org/wiki/Te%C5%9Fkil%C3%A2t-%C4%B1_Esas%C3%AEye_Kanunu"}, +{204,"http://travel.yahoo.com/"}, +{172,"http://tv.yahoo.com/"}, +{770,"http://tv.yahoo.com/news/ncis-exclusive-sopranos-alum-eyed-zivas-successor-debut-205821229.html"}, +{684,"http://tv.yahoo.com/photos/emmys-unrecognizable-emmy-star-transformations-slideshow/"}, +{717,"http://uk.wikipedia.org/wiki/%D0%92%D0%B8%D1%88%D0%BD%D1%96%D0%B9_%D0%A1%D0%BB%D0%B0%D0%B2%D0%BA%D0%BE%D0%B2"}, +{801,"http://vi.wikipedia.org/wiki/Tr%C6%B0%E1%BB%9Dng_THPT_chuy%C3%AAn_L%C6%B0%C6%A1ng_V%C4%83n_Ch%C3%A1nh"}, +{1046,"http://vi.wikipedia.org/wiki/X%E1%BA%BFp_h%E1%BA%A1ng_tr%C6%B0%E1%BB%9Dng_trung_h%E1%BB%8Dc_ph%E1%BB%95_th%C3%B4ng_Vi%E1%BB%87t_Nam"}, +{232,"http://viaf.org/viaf/94287141"}, +{684,"http://voices.washingtonpost.com/dcsportsbog/2007/04/on_caron_butler_and_straws.html"}, +{436,"http://war.wikipedia.org/wiki/Vy%C5%A1n%C3%BD_Slavkov"}, +{505,"http://washingtontimes.com/sports/20060417-122458-4991r_page2.htm"}, +{204,"http://weather.yahoo.com"}, +{404,"http://weather.yahoo.com/forecast/JAXX0077_f.html"}, +{740,"http://web.archive.org/web/20040603025509/http://www.usabasketball.com/history/ymwc_2001.html"}, +{260,"http://wikimediafoundation.org/"}, +{412,"http://wikimediafoundation.org/wiki/Privacy_policy"}, +{396,"http://wikimediafoundation.org/wiki/Terms_of_Use"}, +{308,"http://www.anayasa.gen.tr/1921tek.htm"}, +{492,"http://www.basketball-reference.com/players/b/butleca01.html"}, +{587,"http://www.basketballreference.com/players/playerpage.htm?ilkid=BUTLECA01"}, +{380,"http://www.bilkent.edu.tr/~genckaya/1921C.html"}, +{308,"http://www.caronbutlersummercamp.com/"}, +{308,"http://www.daao.org.au/main/read/2355"}, +{386,"http://www.ebi.ac.uk/QuickGO/GProtein?ac=P30046"}, +{1416,"http://www.ebi.ac.uk/pdbe/searchResults.html?display=both&term=P30046%20or%20Q53Y51%20or%20E2RQU0%20or%20A5PK65%20or%20O35215%20or%20Q3UNI8%20or%20P80254%20or%20Q5ZMG0%20or%20Q6IQL4"}, +{574,"http://www.ensembl.org/Homo_sapiens/geneview?gene=ENSG00000099977;db=core"}, +{591,"http://www.ensembl.org/Mus_musculus/geneview?gene=ENSMUSG00000001666;db=core"}, +{188,"http://www.flickr.com/"}, +{550,"http://www.flickr.com/photos/yahooeditorspicks/galleries/72157635598104765"}, +{901,"http://www.flickr.com/photos/yahooeditorspicks/galleries/72157635598104765/with/7037921709/lightbox/?yc=www.yahoo.com"}, +{952,"http://www.fool.com/investing/general/2013/09/16/3-car-brands-that-may-disappear-before-2020.aspx?source=eogyholnk0000001"}, +{576,"http://www.genecards.org/cgi-bin/carddisp.pl?id_type=entrezgene&id=1652"}, +{456,"http://www.genenames.org/data/hgnc_data.php?hgnc_id=2732"}, +{443,"http://www.genome.jp/dbget-bin/www_bget?enzyme+4.1.1.84"}, +{404,"http://www.gutenberg.org/author/Johann_David_Wyss"}, +{597,"http://www.informatics.jax.org/searches/accession_report.cgi?id=MGI:1298381"}, +{212,"http://www.intonow.com/ci"}, +{348,"http://www.leighrayment.com/baronetage.htm"}, +{444,"http://www.london-gazette.co.uk/issues/21964/pages/379"}, +{436,"http://www.mapress.com/zootaxa/2010/f/z02583p119f.pdf"}, +{340,"http://www.mapress.com/zootaxa/index.html"}, +{212,"http://www.mediawiki.org/"}, +{544,"http://www.nba.com/allstar2007/news/allstar_reserves_070201.html"}, +{332,"http://www.nba.com/news/pow_070122.html"}, +{348,"http://www.nba.com/playerfile/caron_butler"}, +{356,"http://www.nba.com/playerfile/caron_butler/"}, +{492,"http://www.nba.com/suns/news/suns-trade-kravtsov-smith-bucks"}, +{588,"http://www.nba.com/suns/suns-complete-deal-eric-bledsoe-and-caron-butler"}, +{832,"http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=homologene&dopt=HomoloGene&list_uids=1038"}, +{812,"http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=retrieve&dopt=default&list_uids=13202&rn=1"}, +{804,"http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=retrieve&dopt=default&list_uids=1652&rn=1"}, +{488,"http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?val=NM_001084392"}, +{478,"http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?val=NM_010027"}, +{405,"http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1219731"}, +{400,"http://www.ncbi.nlm.nih.gov/pmc/articles/PMC139241"}, +{405,"http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1847948"}, +{344,"http://www.ncbi.nlm.nih.gov/pubmed/10079069"}, +{341,"http://www.ncbi.nlm.nih.gov/pubmed/1286669"}, +{341,"http://www.ncbi.nlm.nih.gov/pubmed/8267597"}, +{688,"http://www.ncbi.nlm.nih.gov/sites/entrez?Db=gene&Cmd=ShowDetailView&TermToSearch=1652"}, +{747,"http://www.ncbi.nlm.nih.gov/sites/entrez?db=gene&cmd=Link&LinkName=gene_pubmed&from_uid=13202"}, +{744,"http://www.ncbi.nlm.nih.gov/sites/entrez?db=gene&cmd=Link&LinkName=gene_pubmed&from_uid=1652"}, +{428,"http://www.oprah.com/oprahshow/Overcoming-the-Odds/8"}, +{428,"http://www.oprah.com/oprahshow/Overcoming-the-Odds/9"}, +{412,"http://www.rcsb.org/pdb/cgi/explore.cgi?pdbId=1DPT"}, +{1322,"http://www.rcsb.org/pdb/search/smartSubquery.do?smartSearchSubtype=UpAccessionIdQuery&accessionIdList=P30046,Q53Y51,E2RQU0,A5PK65,O35215,Q3UNI8,P80254,Q5ZMG0,Q6IQL4"}, +{806,"http://www.sbnation.com/golf/2013/9/17/4737628/bmw-championship-2013-tiger-woods-penalty-johnny-miller"}, +{364,"http://www.statistics.sk/mosmis/eng/run.html"}, +{188,"http://www.tbmm.gov.tr"}, +{372,"http://www.tbmm.gov.tr/english/about_tgna.htm"}, +{212,"http://www.thepeerage.com"}, +{284,"http://www.thepeerage.com/info.htm"}, +{585,"http://www.uconnhuskies.com/AllStories/MBasketball/2002/06/26/20020626.html"}, +{304,"http://www.uniprot.org/uniprot/O35215"}, +{304,"http://www.uniprot.org/uniprot/P30046"}, +{644,"http://www.washingtonpost.com/wp-dyn/content/article/2008/02/16/AR2008021600752_2.html"}, +{293,"http://www.wikidata.org/wiki/Q115822"}, +{460,"http://www.wikidata.org/wiki/Q115822#sitelinks-wikipedia"}, +{292,"http://www.wikimediafoundation.org/"}, +{172,"http://www.yahoo.com"}, +{180,"http://www.yahoo.com/"}, +{188,"http://www.yahoo.com/#"}, +{276,"http://www.yahoo.com/#suggestions"}, +{244,"http://www.yahoo.com/?hps=210"}, +{444,"http://yahoo.match.com?trackingid=526100&bannerid=673168"}, +{535,"http://zh.wikipedia.org/wiki/%E5%8D%A1%E9%9A%86%C2%B7%E5%B7%B4%E7%89%B9%E5%8B%92"}, +{1164,"https://donate.wikimedia.org/wiki/Special:FundraiserRedirector?utm_source=donate&utm_medium=sidebar&utm_campaign=C13_en.wikipedia.org&uselang=en"}, +{740,"https://edit.yahoo.com/registration?.src=fpctx&.intl=us&.done=http%3A%2F%2Fwww.yahoo.com%2F"}, +{748,"https://login.yahoo.com/config/login?.src=fpctx&.intl=us&.done=http%3A%2F%2Fwww.yahoo.com%2F"}, +{548,"https://www.mediawiki.org/wiki/Special:MyLanguage/How_to_contribute"}, +{0,NULL} +}; diff --git a/genqrcode/tests/common.c b/genqrcode/tests/common.c new file mode 100644 index 0000000000..696a94b3a5 --- /dev/null +++ b/genqrcode/tests/common.c @@ -0,0 +1,285 @@ +#include <stdio.h> +#include <stdlib.h> +#include "common.h" + +static int tests = 0; +static int failed = 0; +int assertionFailed = 0; +int assertionNum = 0; +static const char *testName = NULL; +static const char *testFunc = NULL; + +const char levelChar[4] = {'L', 'M', 'Q', 'H'}; +const char *modeStr[5] = {"nm", "an", "8", "kj", "st"}; + +int ncmpBin(char *correct, BitStream *bstream, size_t len) +{ + int bit; + size_t i; + char *p; + + if(len != BitStream_size(bstream)) { + printf("Length is not match: %zu, %zu expected.\n", BitStream_size(bstream), len); + return -1; + } + + p = correct; + i = 0; + while(*p != '\0') { + while(*p == ' ') { + p++; + } + bit = (*p == '1')?1:0; + if(bstream->data[i] != bit) return -1; + i++; + p++; + if(i == len) break; + } + + return 0; +} + +int cmpBin(char *correct, BitStream *bstream) +{ + size_t len = 0; + char *p; + + + for(p = correct; *p != '\0'; p++) { + if(*p != ' ') len++; + } + return ncmpBin(correct, bstream, len); +} + +void testInit(int testnum) +{ + printf("1..%d\n", testnum); +} + +void testStartReal(const char *func, const char *name) +{ + tests++; + testName = name; + testFunc = func; + assertionFailed = 0; + assertionNum = 0; + //printf("_____%d: %s: %s...\n", tests, func, name); +} + +void testEnd(int result) +{ + if(result) { + printf("not ok %d %s: %s\n", tests, testFunc, testName); + failed++; + } else { + printf("ok %d %s: %s\n", tests, testFunc, testName); + } +} + +void testFinish(void) +{ + if(assertionFailed) { + printf("not ok %d %s: %s (%d assertions failed.)\n", tests, testFunc, testName, assertionFailed); + failed++; + } else { + printf("ok %d %s: %s (%d assertions passed.)\n", tests, testFunc, testName, assertionNum); + } +} + +void testReport(int expectedTests) +{ + printf("Total %d tests, %d fails.\n", tests, failed); + if(failed) exit(-1); + if(expectedTests != tests) { + printf("WARNING: the number of the executed tests (%d) is not equal to the expecetd (%d).\n", tests, expectedTests); + } +} + +void printBinary(unsigned char *data, size_t length) +{ + size_t i; + + for(i=0; i<length; i++) { + printf(data[i]?"1":"0"); + } + printf("\n"); +} + +void printBstream(BitStream *bstream) +{ + printBinary(bstream->data, BitStream_size(bstream)); +} + +void printQRinput(QRinput *input) +{ + QRinput_List *list; + int i; + + list = input->head; + while(list != NULL) { + for(i=0; i<list->size; i++) { + printf("0x%02x,", list->data[i]); + } + list = list->next; + } + printf("\n"); +} + +void printQRinputInfo(QRinput *input) +{ + QRinput_List *list; + BitStream *b; + int i, ret; + + printf("QRinput info:\n"); + printf(" version: %d\n", input->version); + printf(" level : %c\n", levelChar[input->level]); + list = input->head; + i = 0; + while(list != NULL) { + i++; + list = list->next; + } + printf(" chunks: %d\n", i); + b = BitStream_new(); + ret = QRinput_mergeBitStream(input, b); + if(ret == 0) { + printf(" bitstream-size: %zu\n", BitStream_size(b)); + BitStream_free(b); + } + + list = input->head; + i = 0; + while(list != NULL) { + printf("\t#%d: mode = %s, size = %d\n", i, modeStr[list->mode], list->size); + i++; + list = list->next; + } +} + +void printQRinputStruct(QRinput_Struct *s) +{ + QRinput_InputList *list; + int i = 1; + + printf("Struct size: %d\n", s->size); + printf("Struct parity: %08x\n", s->parity); + for(list = s->head; list != NULL; list = list->next) { + printf("Symbol %d - ", i); + printQRinputInfo(list->input); + i++; + } +} + +void printFrame(int width, unsigned char *frame) +{ + int x, y; + + for(y=0; y<width; y++) { + for(x=0; x<width; x++) { + printf("%02x ", *frame++); + } + printf("\n"); + } +} + +void printQRcode(QRcode *code) +{ + printFrame(code->width, code->data); +} + +void printQRRawCodeFromQRinput(QRinput *input) +{ + QRRawCode *raw; + int i; + + puts("QRRawCode dump image:"); + raw = QRraw_new(input); + if(raw == NULL) { + puts("Failed to generate QRRawCode from this input.\n"); + return; + } + for(i=0; i<raw->dataLength; i++) { + printf(" %02x", raw->datacode[i]); + } + for(i=0; i<raw->eccLength; i++) { + printf(" %02x", raw->ecccode[i]); + } + printf("\n"); + QRraw_free(raw); +} + +#if HAVE_SDL +/* Experimental debug function */ +/* You can call show_QRcode(QRcode *code) to display the QR Code from anywhere + * in test code using SDL. */ +#include <SDL.h> + +static void draw_QRcode(QRcode *qrcode, int ox, int oy, int margin, int size, SDL_Surface *surface) +{ + int x, y, width; + unsigned char *p; + SDL_Rect rect; + Uint32 color[2]; + + color[0] = SDL_MapRGBA(surface->format, 255, 255, 255, 255); + color[1] = SDL_MapRGBA(surface->format, 0, 0, 0, 255); + SDL_FillRect(surface, NULL, color[0]); + + ox += margin * size; + oy += margin * size; + width = qrcode->width; + p = qrcode->data; + for(y=0; y<width; y++) { + for(x=0; x<width; x++) { + rect.x = ox + x * size; + rect.y = oy + y * size; + rect.w = size; + rect.h = size; + SDL_FillRect(surface, &rect, color[*p&1]); + p++; + } + } +} + +void show_QRcode(QRcode *qrcode) +{ + SDL_Event event; + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Surface *surface; + SDL_Texture *texture; + + if(!SDL_WasInit(SDL_INIT_VIDEO)) { + SDL_Init(SDL_INIT_VIDEO); + atexit(SDL_Quit); + } + int width = (qrcode->width + 4 * 2) * 4; //maring = 4, size = 4 + SDL_CreateWindowAndRenderer(width, width, SDL_WINDOW_SHOWN, &window, &renderer); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderClear(renderer); + surface = SDL_CreateRGBSurface(0, width, width, 32, 0, 0, 0, 0); + + draw_QRcode(qrcode, 0, 0, 4, 4, surface); + + texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + fprintf(stderr, "Press any key on the QR Code window to proceed.\n"); + + int loop = 1; + while(loop) { + SDL_WaitEvent(&event); + if(event.type == SDL_KEYDOWN) { + loop = 0; + } + } + + SDL_FreeSurface(surface); + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); +} +#else +void show_QRcode(QRcode *qrcode) { +} +#endif diff --git a/genqrcode/tests/common.h b/genqrcode/tests/common.h new file mode 100644 index 0000000000..ddd2e1460e --- /dev/null +++ b/genqrcode/tests/common.h @@ -0,0 +1,56 @@ +/* + * common part of test units. + */ + +#ifndef COMMON_H__ +#define COMMON_H__ + +#include <stdlib.h> +#if HAVE_CONFIG_H +#include "../config.h" +#endif +#include "../qrencode.h" +#include "../qrinput.h" +#include "../bitstream.h" +#include "../qrencode_inner.h" + +extern int assertionFailed; +extern int assertionNum; +extern const char levelChar[4]; +extern const char *modeStr[5]; + +void testInit(int tests); +#define testStart(__arg__) (testStartReal(__func__, __arg__)) +#define testEndExp(__arg__) (testEnd(!(__arg__))) +void testStartReal(const char *func, const char *name); +void testEnd(int result); +void testFinish(void); +void testReport(int tests); + +#define assert_exp(__exp__, ...) \ +{assertionNum++;if(!(__exp__)) {assertionFailed++; printf(__VA_ARGS__);}} + +#define assert_zero(__exp__, ...) assert_exp((__exp__) == 0, __VA_ARGS__) +#define assert_nonzero(__exp__, ...) assert_exp((__exp__) != 0, __VA_ARGS__) +#define assert_null(__ptr__, ...) assert_exp((__ptr__) == NULL, __VA_ARGS__) +#define assert_nonnull(__ptr__, ...) assert_exp((__ptr__) != NULL, __VA_ARGS__) +#define assert_equal(__e1__, __e2__, ...) assert_exp((__e1__) == (__e2__), __VA_ARGS__) +#define assert_notequal(__e1__, __e2__, ...) assert_exp((__e1__) != (__e2__), __VA_ARGS__) +#define assert_nothing(__exp__, ...) {printf(__VA_ARGS__); __exp__;} + +int ncmpBin(char *correct, BitStream *bstream, size_t len); +int cmpBin(char *correct, BitStream *bstream); + +void printFrame(int width, unsigned char *frame); +void printQRcode(QRcode *code); +void printQRRawCodeFromQRinput(QRinput *input); +void printQRinput(QRinput *input); +void printQRinputInfo(QRinput *input); +void printQRinputStruct(QRinput_Struct *s); + +void printBinary(unsigned char *data, size_t length); +void printBstream(BitStream *bstream); + +void show_QRcode(QRcode *qrcode); + +#endif /* COMMON_H__ */ diff --git a/genqrcode/tests/create_frame_pattern.c b/genqrcode/tests/create_frame_pattern.c new file mode 100644 index 0000000000..786309fe52 --- /dev/null +++ b/genqrcode/tests/create_frame_pattern.c @@ -0,0 +1,170 @@ +/* + * This tool creates a frame pattern data for debug purpose used by + * test_qrspec. test_qrspec and create_frame_pattern uses the same function + * of libqrencode. This means the test is meaningless if test_qrspec is run + * with a pattern data created by create_frame_pattern of the same version. + * In order to test it correctly, create a pattern data by the tool of the + * previous version, or use the frame data attached to the package. + */ + +#include <stdio.h> +#include <string.h> +#include <png.h> +#include "common.h" +#include "../qrspec.h" + +void append_pattern(int version, FILE *fp) +{ + int width; + unsigned char *frame; + + frame = QRspec_newFrame(version); + width = QRspec_getWidth(version); + fwrite(frame, 1, width * width, fp); + free(frame); +} + +static int writePNG(unsigned char *frame, int width, const char *outfile) +{ + static FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + unsigned char *row, *p, *q; + int x, y, xx, yy, bit; + int realwidth; + const int margin = 0; + const int size = 1; + + realwidth = (width + margin * 2) * size; + row = (unsigned char *)malloc((realwidth + 7) / 8); + if(row == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + if(outfile[0] == '-' && outfile[1] == '\0') { + fp = stdout; + } else { + fp = fopen(outfile, "wb"); + if(fp == NULL) { + fprintf(stderr, "Failed to create file: %s\n", outfile); + perror(NULL); + exit(EXIT_FAILURE); + } + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(png_ptr == NULL) { + fclose(fp); + fprintf(stderr, "Failed to initialize PNG writer.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if(info_ptr == NULL) { + fclose(fp); + fprintf(stderr, "Failed to initialize PNG write.\n"); + exit(EXIT_FAILURE); + } + + if(setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + fprintf(stderr, "Failed to write PNG image.\n"); + exit(EXIT_FAILURE); + } + + png_init_io(png_ptr, fp); + png_set_IHDR(png_ptr, info_ptr, + realwidth, realwidth, + 1, + PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info(png_ptr, info_ptr); + + /* top margin */ + memset(row, 0xff, (realwidth + 7) / 8); + for(y=0; y<margin * size; y++) { + png_write_row(png_ptr, row); + } + + /* data */ + p = frame; + for(y=0; y<width; y++) { + bit = 7; + memset(row, 0xff, (realwidth + 7) / 8); + q = row; + q += margin * size / 8; + bit = 7 - (margin * size % 8); + for(x=0; x<width; x++) { + for(xx=0; xx<size; xx++) { + *q ^= (*p & 1) << bit; + bit--; + if(bit < 0) { + q++; + bit = 7; + } + } + p++; + } + for(yy=0; yy<size; yy++) { + png_write_row(png_ptr, row); + } + } + /* bottom margin */ + memset(row, 0xff, (realwidth + 7) / 8); + for(y=0; y<margin * size; y++) { + png_write_row(png_ptr, row); + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + free(row); + + return 0; +} + +void write_pattern_image(int version, const char *filename) +{ + int width; + unsigned char *frame; + static char str[256]; + + frame = QRspec_newFrame(version); + width = QRspec_getWidth(version); + + snprintf(str, 256, "%s-%d.png", filename, version); + writePNG(frame, width, str); + free(frame); +} + +void write_pattern(const char *filename) +{ + FILE *fp; + int i; + + fp = fopen(filename, "wb"); + if(fp == NULL) { + perror("Failed to open a file to write:"); + abort(); + } + for(i=1; i<=QRSPEC_VERSION_MAX; i++) { + append_pattern(i, fp); + write_pattern_image(i, filename); + } + fclose(fp); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + printf("Create empty frame patterns.\nUsage: %s FILENAME\n", argv[0]); + exit(0); + } + write_pattern(argv[1]); + return 0; +} diff --git a/genqrcode/tests/create_mqr_frame_pattern.c b/genqrcode/tests/create_mqr_frame_pattern.c new file mode 100644 index 0000000000..cad1f9c513 --- /dev/null +++ b/genqrcode/tests/create_mqr_frame_pattern.c @@ -0,0 +1,170 @@ +/* + * This tool creates a frame pattern data for debug purpose used by + * test_qrspec. test_qrspec and create_frame_pattern uses the same function + * of libqrencode. This means the test is meaningless if test_qrspec is run + * with a pattern data created by create_frame_pattern of the same version. + * In order to test it correctly, create a pattern data by the tool of the + * previous version, or use the frame data attached to the package. + */ + +#include <stdio.h> +#include <string.h> +#include <png.h> +#include "common.h" +#include "../mqrspec.h" + +void append_pattern(int version, FILE *fp) +{ + int width; + unsigned char *frame; + + frame = MQRspec_newFrame(version); + width = MQRspec_getWidth(version); + fwrite(frame, 1, width * width, fp); + free(frame); +} + +static int writePNG(unsigned char *frame, int width, const char *outfile) +{ + static FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + unsigned char *row, *p, *q; + int x, y, xx, yy, bit; + int realwidth; + const int margin = 0; + const int size = 1; + + realwidth = (width + margin * 2) * size; + row = (unsigned char *)malloc((realwidth + 7) / 8); + if(row == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + if(outfile[0] == '-' && outfile[1] == '\0') { + fp = stdout; + } else { + fp = fopen(outfile, "wb"); + if(fp == NULL) { + fprintf(stderr, "Failed to create file: %s\n", outfile); + perror(NULL); + exit(EXIT_FAILURE); + } + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(png_ptr == NULL) { + fclose(fp); + fprintf(stderr, "Failed to initialize PNG writer.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if(info_ptr == NULL) { + fclose(fp); + fprintf(stderr, "Failed to initialize PNG write.\n"); + exit(EXIT_FAILURE); + } + + if(setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + fprintf(stderr, "Failed to write PNG image.\n"); + exit(EXIT_FAILURE); + } + + png_init_io(png_ptr, fp); + png_set_IHDR(png_ptr, info_ptr, + realwidth, realwidth, + 1, + PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info(png_ptr, info_ptr); + + /* top margin */ + memset(row, 0xff, (realwidth + 7) / 8); + for(y=0; y<margin * size; y++) { + png_write_row(png_ptr, row); + } + + /* data */ + p = frame; + for(y=0; y<width; y++) { + bit = 7; + memset(row, 0xff, (realwidth + 7) / 8); + q = row; + q += margin * size / 8; + bit = 7 - (margin * size % 8); + for(x=0; x<width; x++) { + for(xx=0; xx<size; xx++) { + *q ^= (*p & 1) << bit; + bit--; + if(bit < 0) { + q++; + bit = 7; + } + } + p++; + } + for(yy=0; yy<size; yy++) { + png_write_row(png_ptr, row); + } + } + /* bottom margin */ + memset(row, 0xff, (realwidth + 7) / 8); + for(y=0; y<margin * size; y++) { + png_write_row(png_ptr, row); + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + free(row); + + return 0; +} + +void write_pattern_image(int version, const char *filename) +{ + int width; + unsigned char *frame; + static char str[256]; + + frame = MQRspec_newFrame(version); + width = MQRspec_getWidth(version); + + snprintf(str, 256, "%s-M%d.png", filename, version); + writePNG(frame, width, str); + free(frame); +} + +void write_pattern(const char *filename) +{ + FILE *fp; + int i; + + fp = fopen(filename, "wb"); + if(fp == NULL) { + perror("Failed to open a file to write:"); + abort(); + } + for(i=1; i<=MQRSPEC_VERSION_MAX; i++) { + append_pattern(i, fp); + write_pattern_image(i, filename); + } + fclose(fp); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + printf("Create empty frame patterns.\nUsage: %s FILENAME\n", argv[0]); + exit(0); + } + write_pattern(argv[1]); + return 0; +} diff --git a/genqrcode/tests/datachunk.c b/genqrcode/tests/datachunk.c new file mode 100644 index 0000000000..62bb2f964c --- /dev/null +++ b/genqrcode/tests/datachunk.c @@ -0,0 +1,178 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iconv.h> +#include "datachunk.h" + +DataChunk *DataChunk_new(QRencodeMode mode) +{ + DataChunk *chunk; + + chunk = (DataChunk *)calloc(1, sizeof(DataChunk)); + if(chunk == NULL) return NULL; + + chunk->mode = mode; + + return chunk; +} + +void DataChunk_free(DataChunk *chunk) +{ + if(chunk) { + if(chunk->data) free(chunk->data); + free(chunk); + } +} + +void DataChunk_freeList(DataChunk *list) +{ + DataChunk *next; + + while(list != NULL) { + next = list->next; + DataChunk_free(list); + list = next; + } +} + +static void dumpNum(DataChunk *chunk) +{ + printf("%s\n", chunk->data); +} + +static void dumpAn(DataChunk *chunk) +{ + printf("%s\n", chunk->data); +} + +static void dump8(DataChunk *chunk) +{ + size_t i, j; + unsigned char c; + size_t count = 0; + unsigned char buf[16]; + + for(i=0; i<chunk->size; i++) { + buf[count] = chunk->data[i]; + c = chunk->data[i]; + if(c >= ' ' && c <= '~') { + putchar(c); + } else { + putchar('.'); + } + count++; + + if(count >= 16) { + putchar(' '); + for(j=0; j<16; j++) { + printf(" %02x", buf[j]); + } + count = 0; + putchar('\n'); + } + } + if(count > 0) { + for(i=0; i<16 - count; i++) { + putchar(' '); + } + putchar(' '); + for(j=0; j<count; j++) { + printf(" %02x", buf[j]); + } + count = 0; + putchar('\n'); + } +} + +static void dumpKanji(DataChunk *chunk) +{ + iconv_t conv; + char *inbuf, *outbuf, *outp; + size_t inbytes, outbytes, ret; + + conv = iconv_open("UTF-8", "SHIFT_JIS"); + inbytes = chunk->size; + inbuf = (char *)chunk->data; + outbytes = inbytes * 4 + 1; + outbuf = (char *)malloc(inbytes * 4 + 1); + outp = outbuf; + ret = iconv(conv, &inbuf, &inbytes, &outp, &outbytes); + if(ret == (size_t) -1) { perror(NULL); } + *outp = '\0'; + + printf("%s\n", outbuf); + + iconv_close(conv); + free(outbuf); +} + +static void dumpChunk(DataChunk *chunk) +{ + switch(chunk->mode) { + case QR_MODE_NUM: + printf("Numeric: %zu bytes\n", chunk->size); + dumpNum(chunk); + break; + case QR_MODE_AN: + printf("AlphaNumeric: %zu bytes\n", chunk->size); + dumpAn(chunk); + break; + case QR_MODE_8: + printf("8-bit data: %zu bytes\n", chunk->size); + dump8(chunk); + break; + case QR_MODE_KANJI: + printf("Kanji: %zu bytes\n", chunk->size); + dumpKanji(chunk); + break; + case QR_MODE_NUL: + case QR_MODE_STRUCTURE: + case QR_MODE_ECI: + case QR_MODE_FNC1FIRST: + case QR_MODE_FNC1SECOND: + printf("Invalid or reserved: %zu bytes\n", chunk->size); + dump8(chunk); + break; + } +} + +void DataChunk_dumpChunkList(DataChunk *list) +{ + while(list != NULL) { + dumpChunk(list); + list = list->next; + } +} + +int DataChunk_totalSize(DataChunk *list) +{ + int size = 0; + + while(list != NULL) { + size += list->size; + list = list->next; + } + + return size; +} + +unsigned char *DataChunk_concatChunkList(DataChunk *list, int *retsize) +{ + int size, idx; + unsigned char *data; + + size = DataChunk_totalSize(list); + if(size <= 0) return NULL; + + data = (unsigned char *)malloc((size_t)size + 1); + idx = 0; + while(list != NULL) { + memcpy(&data[idx], list->data, list->size); + idx += list->size; + list = list->next; + } + data[size] = '\0'; + + *retsize = size; + return data; +} diff --git a/genqrcode/tests/datachunk.h b/genqrcode/tests/datachunk.h new file mode 100644 index 0000000000..8ef076c4fa --- /dev/null +++ b/genqrcode/tests/datachunk.h @@ -0,0 +1,20 @@ +#ifndef DATACHUNK_H +#define DATACHUNK_H + +#include "../qrencode.h" + +typedef struct _DataChunk { + QRencodeMode mode; + size_t size; + unsigned char *data; + struct _DataChunk *next; +} DataChunk; + +DataChunk *DataChunk_new(QRencodeMode mode); +void DataChunk_free(DataChunk *chunk); +void DataChunk_freeList(DataChunk *list); +void DataChunk_dumpChunkList(DataChunk *list); +int DataChunk_totalSize(DataChunk *list); +unsigned char *DataChunk_concatChunkList(DataChunk *list, int *retsize); + +#endif /* DATACHUNK_H */ diff --git a/genqrcode/tests/decoder.c b/genqrcode/tests/decoder.c new file mode 100644 index 0000000000..706dc31e40 --- /dev/null +++ b/genqrcode/tests/decoder.c @@ -0,0 +1,953 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <iconv.h> +#if HAVE_CONFIG_H +#include "../config.h" +#endif +#include "../qrspec.h" +#include "../bitstream.h" +#include "../mask.h" +#include "../mqrspec.h" +#include "../mmask.h" +#include "common.h" +#include "decoder.h" + +static unsigned int bitToInt(unsigned char *bits, int length) +{ + int i; + unsigned int val = 0; + + for(i=0; i<length; i++) { + val = val << 1; + val |= (bits[i] & 1); + } + + return val; +} + +static int decodeLength(int *bits_length, unsigned char **bits, QRencodeMode mode, int version, int mqr) +{ + int i; + int length = 0; + int lbits; + + if(mqr) { + lbits = MQRspec_lengthIndicator(mode, version); + } else { + lbits = QRspec_lengthIndicator(mode, version); + } + + if(*bits_length < lbits) { + printf("Bit length is too short: %d\n", *bits_length); + return 0; + } + + length = 0; + for(i=0; i<lbits; i++) { + length = length << 1; + length += (*bits)[i]; + } + + *bits_length -= lbits; + *bits += lbits; + + return length; +} + +static DataChunk *decodeNum(int *bits_length, unsigned char **bits, int version, int mqr) +{ + int i; + int size, sizeInBit, words, remain; + unsigned char *p; + char *buf, *q; + unsigned int val; + DataChunk *chunk; + + size = decodeLength(bits_length, bits, QR_MODE_NUM, version, mqr); + if(size < 0) return NULL; + + words = size / 3; + remain = size - words * 3; + sizeInBit = words * 10; + if(remain == 2) { + sizeInBit += 7; + } else if(remain == 1) { + sizeInBit += 4; + } + if(*bits_length < sizeInBit) { + printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit); + return NULL; + } + + buf = (char *)malloc((size_t)size + 1); + p = *bits; + q = buf; + for(i=0; i<words; i++) { + val = bitToInt(p, 10); + sprintf(q, "%03d", val); + p += 10; + q += 3; + } + if(remain == 2) { + val = bitToInt(p, 7); + sprintf(q, "%02d", val); + } else if(remain == 1) { + val = bitToInt(p, 4); + sprintf(q, "%1d", val); + } + buf[size] = '\0'; + + chunk = DataChunk_new(QR_MODE_NUM); + chunk->size = size; + chunk->data = (unsigned char *)buf; + *bits_length -= sizeInBit; + *bits += sizeInBit; + + return chunk; +} + +static const char decodeAnTable[45] = { + '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', ' ', '$', '%', '*', + '+', '-', '.', '/', ':' +}; + +static DataChunk *decodeAn(int *bits_length, unsigned char **bits, int version, int mqr) +{ + int i; + int size, sizeInBit, words, remain; + unsigned char *p; + char *buf, *q; + unsigned int val; + int ch, cl; + DataChunk *chunk; + + size = decodeLength(bits_length, bits, QR_MODE_AN, version, mqr); + if(size < 0) return NULL; + + words = size / 2; + remain = size - words * 2; + sizeInBit = words * 11 + remain * 6; + if(*bits_length < sizeInBit) { + printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit); + return NULL; + } + + buf = (char *)malloc((size_t)size + 1); + p = *bits; + q = buf; + for(i=0; i<words; i++) { + val = bitToInt(p, 11); + ch = (int)(val / 45); + cl = (int)(val % 45); + sprintf(q, "%c%c", decodeAnTable[ch], decodeAnTable[cl]); + p += 11; + q += 2; + } + if(remain == 1) { + val = bitToInt(p, 6); + sprintf(q, "%c", decodeAnTable[val]); + } + + chunk = DataChunk_new(QR_MODE_AN); + chunk->size = size; + chunk->data = (unsigned char *)buf; + *bits_length -= sizeInBit; + *bits += sizeInBit; + + return chunk; +} + +static DataChunk *decode8(int *bits_length, unsigned char **bits, int version, int mqr) +{ + int i; + int size, sizeInBit; + unsigned char *p; + unsigned char *buf, *q; + DataChunk *chunk; + + size = decodeLength(bits_length, bits, QR_MODE_8, version, mqr); + if(size < 0) return NULL; + + sizeInBit = size * 8; + if(*bits_length < sizeInBit) { + printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit); + return NULL; + } + + buf = (unsigned char *)malloc((size_t)size); + p = *bits; + q = buf; + for(i=0; i<size; i++) { + *q = (unsigned char)bitToInt(p, 8); + p += 8; + q += 1; + } + + chunk = DataChunk_new(QR_MODE_8); + chunk->size = size; + chunk->data = buf; + *bits_length -= sizeInBit; + *bits += sizeInBit; + + return chunk; +} + +static DataChunk *decodeKanji(int *bits_length, unsigned char **bits, int version, int mqr) +{ + int i; + int size, sizeInBit; + unsigned char *p; + char *buf, *q; + unsigned int val; + unsigned int ch, cl; + DataChunk *chunk; + + size = decodeLength(bits_length, bits, QR_MODE_KANJI, version, mqr); + if(size < 0) return NULL; + + sizeInBit = size * 13; + if(*bits_length < sizeInBit) { + printf("Bit length is too short: %d, expected %d.\n", *bits_length, sizeInBit); + return NULL; + } + + buf = (char *)malloc((size_t)size * 2 + 1); + p = *bits; + q = buf; + for(i=0; i<size; i++) { + val = bitToInt(p, 13); + ch = val / 0xc0; + cl = val - ch * 0xc0; + val = ch * 256 + cl; + if(val >= 0x1f00) { + val += 0xc140; + } else { + val += 0x8140; + } + sprintf(q, "%c%c", (val>>8) & 0xff, val & 0xff); + p += 13; + q += 2; + } + + chunk = DataChunk_new(QR_MODE_KANJI); + chunk->size = size * 2; + chunk->data = (unsigned char *)buf; + *bits_length -= sizeInBit; + *bits += sizeInBit; + + return chunk; +} + +static DataChunk *decodeChunk(int *bits_length, unsigned char **bits, int version) +{ + unsigned int val; + + if(*bits_length < 4) { + return NULL; + } + val = bitToInt(*bits, 4); + *bits_length -= 4; + *bits += 4; + switch(val) { + case 0: + return NULL; + case 1: + return decodeNum(bits_length, bits, version, 0); + case 2: + return decodeAn(bits_length, bits, version, 0); + case 4: + return decode8(bits_length, bits, version, 0); + case 8: + return decodeKanji(bits_length, bits, version, 0); + default: + break; + } + + printf("Invalid mode in a chunk: %d\n", val); + + return NULL; +} + +static DataChunk *decodeChunkMQR(int *bits_length, unsigned char **bits, int version) +{ + int modebits, termbits; + unsigned int val; + + modebits = version - 1; + termbits = version * 2 + 1; + if(*bits_length >= termbits) { + val = bitToInt(*bits, termbits); + if(val == 0) { + *bits += termbits; + *bits_length -= termbits; + return NULL; + } + } else { + if(*bits_length < modebits) { + val = bitToInt(*bits, *bits_length); + } else { + val = bitToInt(*bits, modebits); + } + if(val == 0) { + return NULL; + } else { + printf("Terminating bits include 1-bit.\n"); + return NULL; + } + } + val = bitToInt(*bits, modebits); + if(version == 4 && val > 3) { + printf("Invalid mode number %d.\n", val); + } + *bits_length -= modebits; + *bits += modebits; + switch(val) { + case 0: + return decodeNum(bits_length, bits, version, 1); + case 1: + return decodeAn(bits_length, bits, version, 1); + case 2: + return decode8(bits_length, bits, version, 1); + case 3: + return decodeKanji(bits_length, bits, version, 1); + default: + break; + } + + printf("Invalid mode in a chunk: %d\n", val); + + return NULL; +} + +static int appendChunk(QRdata *qrdata, int *bits_length, unsigned char **bits) +{ + DataChunk *chunk; + + if(qrdata->mqr) { + chunk = decodeChunkMQR(bits_length, bits, qrdata->version); + } else { + chunk = decodeChunk(bits_length, bits, qrdata->version); + } + if(chunk == NULL) { + return 1; + } + + if(qrdata->last == NULL) { + qrdata->chunks = chunk; + } else { + qrdata->last->next = chunk; + } + qrdata->last = chunk; + + return 0; +} + +QRdata *QRdata_new(void) +{ + QRdata *qrdata; + + qrdata = (QRdata *)calloc(sizeof(QRdata), 1); + if(qrdata == NULL) return NULL; + + qrdata->eccResult = 0; + + return qrdata; +} + +QRdata *QRdata_newMQR(void) +{ + QRdata *qrdata; + + qrdata = QRdata_new(); + if(qrdata == NULL) return NULL; + + qrdata->mqr = 1; + + return qrdata; +} + +void QRdata_free(QRdata *qrdata) +{ + DataChunk_freeList(qrdata->chunks); + if(qrdata->data != NULL) { + free(qrdata->data); + } + free(qrdata); +} + +static int QRdata_decodeBits(QRdata *qrdata, int length, unsigned char *bits) +{ + int ret = 0; + + while(ret == 0) { + ret = appendChunk(qrdata, &length, &bits); + } + + return length; +} + +int QRdata_decodeBitStream(QRdata *qrdata, BitStream *bstream) +{ + return QRdata_decodeBits(qrdata, bstream->length, bstream->data); +} + +void QRdata_dump(QRdata *data) +{ + DataChunk_dumpChunkList(data->chunks); +} + +int QRcode_decodeVersion(QRcode *code) +{ + unsigned int v1, v2; + int x, y, width; + unsigned char *p; + + width = code->width; + if(width < 45) { + return (width - 21)/ 4 + 1; + } + + v1 = 0; + p = code->data + width * (width - 9) + 5; + for(x=0; x<6; x++) { + for(y=0; y<3; y++) { + v1 = v1 << 1; + v1 |= *(p - y * width - x) & 1; + } + } + + v2 = 0; + p = code->data + width * 5 + width - 9; + for(y=0; y<6; y++) { + for(x=0; x<3; x++) { + v2 = v2 << 1; + v2 |= *(p - y * width - x) & 1; + } + } + + if(v1 != v2) { + printf("Two verion patterns are different.\n"); + return -1; + } + + return (int)(v1 >> 12); +} + +int QRcode_decodeFormat(QRcode *code, QRecLevel *level, int *mask) +{ + unsigned int v1, v2; + int i, width; + unsigned char *p; + + width = code->width; + + v1 = 0; + p = code->data + width * 8; + for(i=0; i<8; i++) { + v1 = v1 << 1; + if(i < 6) { + v1 |= *(p + i) & 1; + } else { + v1 |= *(p + i + 1) & 1; + } + } + p = code->data + width * 7 + 8; + for(i=0; i<7; i++) { + v1 = v1 << 1; + if(i < 1) { + v1 |= *(p - width * i) & 1; + } else { + v1 |= *(p - width * (i + 1)) & 1; + } + } + + v2 = 0; + p = code->data + width * (width - 1) + 8; + for(i=0; i<7; i++) { + v2 = v2 << 1; + v2 |= *(p - width * i) & 1; + } + p = code->data + width * 8 + width - 8; + for(i=0; i<8; i++) { + v2 = v2 << 1; + v2 |= *(p + i) & 1; + } + + if(v1 != v2) { + printf("Two format infos are different.\n"); + return -1; + } + v1 = (v1 ^ 0x5412) >> 10; + *mask = v1 & 7; + switch((v1 >> 3) & 3) { + case 1: + *level = QR_ECLEVEL_L; + break; + case 0: + *level = QR_ECLEVEL_M; + break; + case 3: + *level = QR_ECLEVEL_Q; + break; + case 2: + *level = QR_ECLEVEL_H; + break; + default: + break; + } + + return 0; +} + +static unsigned char *unmask(QRcode *code, QRecLevel level, int mask) +{ + unsigned char *unmasked; + + unmasked = Mask_makeMask(code->width, code->data, mask, level); + + return unmasked; +} + +unsigned char *QRcode_unmask(QRcode *code) +{ + int ret, version, mask; + QRecLevel level; + + version = QRcode_decodeVersion(code); + if(version < 1) return NULL; + ret = QRcode_decodeFormat(code, &level, &mask); + if(ret < 0) return NULL; + + return unmask(code, level, mask); +} + +typedef struct { + int width; + unsigned char *frame; + int x, y; + int dir; + int bit; + int mqr; +} FrameFiller; + +static FrameFiller *FrameFiller_new(int width, unsigned char *frame, int mqr) +{ + FrameFiller *filler; + + filler = (FrameFiller *)malloc(sizeof(FrameFiller)); + if(filler == NULL) return NULL; + filler->width = width; + filler->frame = frame; + filler->x = width - 1; + filler->y = width - 1; + filler->dir = -1; + filler->bit = -1; + filler->mqr = mqr; + + return filler; +} + +static unsigned char *FrameFiller_next(FrameFiller *filler) +{ + unsigned char *p; + int x, y, w; + + if(filler->bit == -1) { + filler->bit = 0; + return filler->frame + filler->y * filler->width + filler->x; + } + + x = filler->x; + y = filler->y; + p = filler->frame; + w = filler->width; + + if(filler->bit == 0) { + x--; + filler->bit++; + } else { + x++; + y += filler->dir; + filler->bit--; + } + + if(filler->dir < 0) { + if(y < 0) { + y = 0; + x -= 2; + filler->dir = 1; + if(!filler->mqr && x == 6) { + x--; + y = 9; + } + } + } else { + if(y == w) { + y = w - 1; + x -= 2; + filler->dir = -1; + if(!filler->mqr && x == 6) { + x--; + y -= 8; + } + } + } + if(x < 0 || y < 0) return NULL; + + filler->x = x; + filler->y = y; + + if(p[y * w + x] & 0x80) { + // This tail recursion could be optimized. + return FrameFiller_next(filler); + } + return &p[y * w + x]; +} + +static BitStream *extractBits(int width, unsigned char *frame, int spec[5]) +{ + BitStream *bstream; + unsigned char *bits, *p, *q; + FrameFiller *filler; + int i, j; + int col, row, d1, b1, blocks, idx, words; + + blocks = QRspec_rsBlockNum(spec); + words = QRspec_rsDataLength(spec); + d1 = QRspec_rsDataCodes1(spec); + b1 = QRspec_rsBlockNum1(spec); + bits = (unsigned char *)malloc((size_t)words * 8); + /* + * 00 01 02 03 04 05 06 07 08 09 + * 10 11 12 13 14 15 16 17 18 19 + * 20 21 22 23 24 25 26 27 28 29 30 + * 31 32 33 34 35 36 37 38 39 40 41 + * 42 43 44 45 46 47 48 49 50 51 52 + */ + + row = col = 0; + filler = FrameFiller_new(width, frame, 0); + for(i=0; i<words; i++) { + col = i / blocks; + row = i % blocks + ((col >= d1)?b1:0); + idx = d1 * row + col + ((row > b1)?(row-b1):0); + q = bits + idx * 8; + for(j=0; j<8; j++) { + p = FrameFiller_next(filler); + q[j] = *p & 1; + } + } + free(filler); + + bstream = BitStream_newWithBits((size_t)words * 8, bits); + free(bits); + + return bstream; +} + +BitStream *QRcode_extractBits(QRcode *code, int *dataLength, int *eccLength) +{ + BitStream *bstream; + unsigned char *unmasked; + int spec[5]; + int ret, version, mask; + QRecLevel level; + + version = QRcode_decodeVersion(code); + if(version < 1) return NULL; + ret = QRcode_decodeFormat(code, &level, &mask); + if(ret < 0) return NULL; + + QRspec_getEccSpec(version, level, spec); + + unmasked = unmask(code, level, mask); + if(unmasked == NULL) return NULL; + + bstream = extractBits(code->width, unmasked, spec); + free(unmasked); + + *dataLength = QRspec_rsDataLength(spec) * 8; + *eccLength = QRspec_rsEccLength(spec) * 8; + + return bstream; +} + +static int checkRemainderWords(int length, unsigned char *bits, int remainder) +{ + int rbits, words; + unsigned char *p, v; + int i; + + words = remainder / 8; + rbits = remainder - words * 8; + bits += (length - remainder); + for(i=0; i<rbits; i++) { + if((bits[i]&1) != 0) { + printf("Terminating code includes 1-bit.\n"); + printBinary(bits, remainder); + return -1; + } + } + p = bits + rbits; + for(i=0; i<words; i++) { + v = (unsigned char)bitToInt(p, 8); + if(v != ((i&1)?0x11:0xec)) { + printf("Remainder codewords wrong.\n"); + printBinary(bits, remainder); + return -1; + } + p += 8; + } + + return 0; +} + +QRdata *QRcode_decodeBits(QRcode *code) +{ + BitStream *bstream; + unsigned char *unmasked; + int spec[5]; + int ret, version, mask; + int length; + QRecLevel level; + QRdata *qrdata; + + version = QRcode_decodeVersion(code); + if(version < 1) return NULL; + ret = QRcode_decodeFormat(code, &level, &mask); + if(ret < 0) return NULL; + + QRspec_getEccSpec(version, level, spec); + length = QRspec_rsDataLength(spec) * 8; + + unmasked = unmask(code, level, mask); + if(unmasked == NULL) return NULL; + + bstream = extractBits(code->width, unmasked, spec); + free(unmasked); + + qrdata = QRdata_new(); + qrdata->version = version; + qrdata->level = level; + ret = QRdata_decodeBitStream(qrdata, bstream); + if(ret > 0) { + checkRemainderWords(length, bstream->data, ret); + } + + BitStream_free(bstream); + + return qrdata; +} + +void QRdata_concatChunks(QRdata *qrdata) +{ + qrdata->data = DataChunk_concatChunkList(qrdata->chunks, &qrdata->size); +} + +QRdata *QRcode_decode(QRcode *code) +{ + QRdata *qrdata; + + qrdata = QRcode_decodeBits(code); + QRdata_concatChunks(qrdata); + + return qrdata; +} + +/* + * Micro QR Code decoder + */ + +struct FormatInfo MQRformat[] = { + {1, QR_ECLEVEL_L}, + {2, QR_ECLEVEL_L}, + {2, QR_ECLEVEL_M}, + {3, QR_ECLEVEL_L}, + {3, QR_ECLEVEL_M}, + {4, QR_ECLEVEL_L}, + {4, QR_ECLEVEL_M}, + {4, QR_ECLEVEL_Q} +}; + +int QRcode_decodeFormatMQR(QRcode *code, int *version, QRecLevel *level, int *mask) +{ + unsigned int v, t; + int i, width; + unsigned char *p; + + width = code->width; + + v = 0; + p = code->data + width * 8 + 1; + for(i=0; i<8; i++) { + v = v << 1; + v |= p[i] & 1; + } + p = code->data + width * 7 + 8; + for(i=0; i<7; i++) { + v = v << 1; + v |= *(p - width * i) & 1; + } + v ^= 0x4445; + *mask = (v >> 10) & 3; + t = (v >> 12) & 7; + *version = MQRformat[t].version; + *level = MQRformat[t].level; + if(*version * 2 + 9 != width) { + printf("Decoded version number does not match to the size.\n"); + return -1; + } + return 0; +} + +static unsigned char *unmaskMQR(QRcode *code, QRecLevel level, int mask) +{ + unsigned char *unmasked; + + unmasked = MMask_makeMask(code->version, code->data, mask, level); + + return unmasked; +} + +unsigned char *QRcode_unmaskMQR(QRcode *code) +{ + int ret, version, mask; + QRecLevel level; + + ret = QRcode_decodeFormatMQR(code, &version, &level, &mask); + if(ret < 0) return NULL; + + return unmaskMQR(code, level, mask); +} + +static BitStream *extractBitsMQR(int width, unsigned char *frame, int version, QRecLevel level) +{ + BitStream *bstream; + unsigned char *bits; + FrameFiller *filler; + int i; + int size; + + size = MQRspec_getDataLengthBit(version, level) + MQRspec_getECCLength(version, level) * 8; + bits = (unsigned char *)malloc((size_t)size); + filler = FrameFiller_new(width, frame, 1); + for(i=0; i<size; i++) { + bits[i] = *(FrameFiller_next(filler)) & 1; + } + free(filler); + + bstream = BitStream_newWithBits((size_t)size, bits); + free(bits); + + return bstream; +} + +BitStream *QRcode_extractBitsMQR(QRcode *code, int *dataLength, int *eccLength, int *version, QRecLevel *level) +{ + BitStream *bstream; + unsigned char *unmasked; + int ret, mask; + + ret = QRcode_decodeFormatMQR(code, version, level, &mask); + if(ret < 0) return NULL; + + unmasked = unmaskMQR(code, *level, mask); + if(unmasked == NULL) return NULL; + + *dataLength = MQRspec_getDataLengthBit(*version, *level); + *eccLength = MQRspec_getECCLength(*version, *level) * 8; + bstream = extractBitsMQR(code->width, unmasked, *version, *level); + free(unmasked); + + return bstream; +} + +static int checkRemainderWordsMQR(int length, unsigned char *bits, int remainder, int version) +{ + int rbits, words, paddings; + unsigned char *p, v; + int i, decoded; + + decoded = length - remainder; + bits += decoded; + words = (decoded + 7) / 8; + rbits = words * 8 - decoded; + for(i=0; i<rbits; i++) { + if((bits[i]&1) != 0) { + printf("Terminating code includes 1-bit.\n"); + printBinary(bits, remainder); + return -1; + } + } + + paddings = (length - words * 8) / 8; + p = bits + rbits; + for(i=0; i<paddings; i++) { + v = (unsigned char)bitToInt(p, 8); + if(v != ((i&1)?0x11:0xec)) { + printf("Remainder codewords wrong.\n"); + printBinary(bits, remainder); + return -1; + } + p += 8; + } + rbits = length - (paddings + words)* 8; + if(rbits > 0) { + if((version == 1 || version == 3) && rbits == 4) { + v = (unsigned char)bitToInt(p, 4); + if(v != 0) { + printf("Last padding bits include 1-bit.\n"); + return -1; + } + } else { + printf("The length of the last padding bits is %d, not %d.\n", rbits, (version == 1 || version == 3)?4:0); + return -1; + } + } + + return 0; +} + +QRdata *QRcode_decodeBitsMQR(QRcode *code) +{ + BitStream *bstream; + int ret, version, dataLength, eccLength; + QRecLevel level; + QRdata *qrdata; + + bstream = QRcode_extractBitsMQR(code, &dataLength, &eccLength, &version, &level); + if(bstream == NULL) { + return NULL; + } + + qrdata = QRdata_newMQR(); + qrdata->version = version; + qrdata->level = level; + ret = QRdata_decodeBits(qrdata, dataLength, bstream->data); + if(ret > 0) { + ret = checkRemainderWordsMQR(dataLength, bstream->data, ret, version); + if(ret < 0) { + QRdata_free(qrdata); + qrdata = NULL; + } + } + + BitStream_free(bstream); + + return qrdata; +} + +QRdata *QRcode_decodeMQR(QRcode *code) +{ + QRdata *qrdata; + qrdata = QRcode_decodeBitsMQR(code); + if(qrdata != NULL) { + QRdata_concatChunks(qrdata); + } + + return qrdata; +} diff --git a/genqrcode/tests/decoder.h b/genqrcode/tests/decoder.h new file mode 100644 index 0000000000..087ec6f108 --- /dev/null +++ b/genqrcode/tests/decoder.h @@ -0,0 +1,43 @@ +#ifndef DECODER_H +#define DECODER_H + +#include "../qrencode.h" +#include "datachunk.h" + +typedef struct { + unsigned char *data; + int size; + int mqr; + int version; + QRecLevel level; + DataChunk *chunks, *last; + int eccResult; +} QRdata; + +struct FormatInfo { + int version; + QRecLevel level; +}; + +extern struct FormatInfo MQRformat[]; + +QRdata *QRdata_new(void); +QRdata *QRdata_newMQR(void); +int QRdata_decodeBitStream(QRdata *qrdata, BitStream *bstream); +void QRdata_dump(QRdata *data); +void QRdata_free(QRdata *data); + +int QRcode_decodeVersion(QRcode *code); +int QRcode_decodeFormat(QRcode *code, QRecLevel *level, int *mask); +unsigned char *QRcode_unmask(QRcode *code); +BitStream *QRcode_extractBits(QRcode *code, int *dataLength, int *eccLength); +QRdata *QRcode_decodeBits(QRcode *code); +QRdata *QRcode_decode(QRcode *code); + +int QRcode_decodeFormatMQR(QRcode *code, int *vesion, QRecLevel *level, int *mask); +unsigned char *QRcode_unmaskMQR(QRcode *code); +BitStream *QRcode_extractBitsMQR(QRcode *code, int *dataLength, int *eccLength, int *version, QRecLevel *level); +QRdata *QRcode_decodeBitsMQR(QRcode *code); +QRdata *QRcode_decodeMQR(QRcode *code); + +#endif /* DECODER_H */ diff --git a/genqrcode/tests/frame b/genqrcode/tests/frame Binary files differnew file mode 100644 index 0000000000..fda4eaaa8a --- /dev/null +++ b/genqrcode/tests/frame diff --git a/genqrcode/tests/prof_qrencode.c b/genqrcode/tests/prof_qrencode.c new file mode 100644 index 0000000000..8aa9a98b95 --- /dev/null +++ b/genqrcode/tests/prof_qrencode.c @@ -0,0 +1,102 @@ +#include <stdio.h> +#include <stdlib.h> +#if HAVE_CONFIG_H +#include "../config.h" +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <errno.h> +#include "../qrencode.h" + +#ifdef _MSC_VER +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +static LARGE_INTEGER startTime; +static LARGE_INTEGER frequency = { .QuadPart = 0 }; +#else +static struct timeval tv; +#endif + +static void timerStart(const char *str) +{ + printf("%s: START\n", str); +#ifdef _MSC_VER + (void) QueryPerformanceCounter(&startTime); +#else + gettimeofday(&tv, NULL); +#endif +} + +static void timerStop(void) +{ +#ifdef _MSC_VER + LARGE_INTEGER endTime, elapsed; + (void) QueryPerformanceCounter(&endTime); + if (frequency.QuadPart == 0) { + (void) QueryPerformanceFrequency(&frequency); + } + + elapsed.QuadPart = endTime.QuadPart - startTime.QuadPart; + elapsed.QuadPart *= 1000; + elapsed.QuadPart /= frequency.QuadPart; + + printf("STOP: %lld msec\n", elapsed.QuadPart); +#else + struct timeval tc; + + gettimeofday(&tc, NULL); + printf("STOP: %ld msec\n", (tc.tv_sec - tv.tv_sec) * 1000 + + (tc.tv_usec - tv.tv_usec) / 1000); +#endif +} + +static void prof_ver1to10(void) +{ + QRcode *code; + int i; + int version; + static const char *data = "This is test."; + + timerStart("Version 1 - 10 (5000 symbols for each)"); + for(i=0; i<5000; i++) { + for(version = 0; version < 11; version++) { + code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0); + if(code == NULL) { + perror("Failed to encode:"); + } else { + QRcode_free(code); + } + } + } + timerStop(); +} + +static void prof_ver31to40(void) +{ + QRcode *code; + int i; + int version; + static const char *data = "This is test."; + + timerStart("Version 31 - 40 (500 symbols for each)"); + for(i=0; i<500; i++) { + for(version = 31; version < 41; version++) { + code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0); + if(code == NULL) { + perror("Failed to encode:"); + } else { + QRcode_free(code); + } + } + } + timerStop(); +} + +int main() +{ + prof_ver1to10(); + prof_ver31to40(); + + return 0; +} diff --git a/genqrcode/tests/pthread_qrencode.c b/genqrcode/tests/pthread_qrencode.c new file mode 100644 index 0000000000..a450e59aa4 --- /dev/null +++ b/genqrcode/tests/pthread_qrencode.c @@ -0,0 +1,135 @@ +#include <stdio.h> +#include <stdlib.h> +#if HAVE_CONFIG_H +#include "../config.h" +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <pthread.h> +#include <errno.h> +#include "../qrencode.h" + +#define THREADS (10) + +static pthread_t threads[THREADS]; + +#ifdef _MSC_VER +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +static LARGE_INTEGER startTime; +static LARGE_INTEGER frequency = { .QuadPart = 0 }; +#else +static struct timeval tv; +#endif + +static void timerStart(const char *str) +{ + printf("%s: START\n", str); +#ifdef _MSC_VER + (void) QueryPerformanceCounter(&startTime); +#else + gettimeofday(&tv, NULL); +#endif +} + +static void timerStop(void) +{ +#ifdef _MSC_VER + LARGE_INTEGER endTime, elapsed; + (void) QueryPerformanceCounter(&endTime); + if (frequency.QuadPart == 0) { + (void) QueryPerformanceFrequency(&frequency); + } + + elapsed.QuadPart = endTime.QuadPart - startTime.QuadPart; + elapsed.QuadPart *= 1000; + elapsed.QuadPart /= frequency.QuadPart; + + printf("STOP: %lld msec\n", elapsed.QuadPart); +#else + struct timeval tc; + + gettimeofday(&tc, NULL); + printf("STOP: %ld msec\n", (tc.tv_sec - tv.tv_sec) * 1000 + + (tc.tv_usec - tv.tv_usec) / 1000); +#endif +} + +static void *encode_ver1to10(void *arg) +{ + QRcode *code; + int i; + int version; + static const char *data = "This is test."; + + for(i=0; i<500; i++) { + for(version = 0; version < 11; version++) { + code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0); + if(code == NULL) { + perror("Failed to encode:"); + } else { + QRcode_free(code); + } + } + } + + return NULL; +} + +static void prof_ver1to10(void) +{ + int i; + + timerStart("Version 1 - 10 (500 symbols for each)"); + for(i=0; i<THREADS; i++) { + pthread_create(&threads[i], NULL, encode_ver1to10, NULL); + } + for(i=0; i<THREADS; i++) { + pthread_join(threads[i], NULL); + } + timerStop(); +} + +static void *encode_ver31to40(void *arg) +{ + QRcode *code; + int i; + int version; + static const char *data = "This is test."; + + for(i=0; i<50; i++) { + for(version = 31; version < 41; version++) { + code = QRcode_encodeString(data, version, QR_ECLEVEL_L, QR_MODE_8, 0); + if(code == NULL) { + perror("Failed to encode:"); + } else { + QRcode_free(code); + } + } + } + + return NULL; +} + +static void prof_ver31to40(void) +{ + int i; + + timerStart("Version 31 - 40 (50 symbols for each)"); + for(i=0; i<THREADS; i++) { + pthread_create(&threads[i], NULL, encode_ver31to40, NULL); + } + for(i=0; i<THREADS; i++) { + pthread_join(threads[i], NULL); + } + timerStop(); +} + +int main() +{ + prof_ver1to10(); + prof_ver31to40(); + + return 0; +} diff --git a/genqrcode/tests/release_check.sh b/genqrcode/tests/release_check.sh new file mode 100755 index 0000000000..8c52f07e04 --- /dev/null +++ b/genqrcode/tests/release_check.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# check version numbers between configure.ac and CMakeLists.txt. + +Configure_major_version=`sed -e '1{s/^.*\[\([0-9]\+\)\].*$/\1/};1!d' ../configure.ac` +Configure_minor_version=`sed -e '2{s/^.*\[\([0-9]\+\)\].*$/\1/};2!d' ../configure.ac` +Configure_micro_version=`sed -e '3{s/^.*\[\([0-9]\+\)\].*$/\1/};3!d' ../configure.ac` + +Configure_version_string="$Configure_major_version.$Configure_minor_version.$Configure_micro_version" + +Cmake_version_string=`grep project ../CMakeLists.txt | sed 's/^.*VERSION \([^ ]\+\) .*$/\1/'` + +if [ "$Configure_version_string" != "$Cmake_version_string" ]; then + echo "ERROR: Version number defined in configure.ac is not equal to the number defined in CMakeLists.txt." + echo "configure.ac: $Configure_version_string" + echo "CMakeLists.txt: $Cmake_version_string" +fi + +NEWS_version_string=`grep -m 1 Version ../NEWS | sed 's/^Version \([^ ]\+\) (.*$/\1/'` + +if [ "$Configure_version_string" != "$NEWS_version_string" ]; then + echo "ERROR: Version number defined in configure.ac is not equal to the newest number described in NEWS." + echo "configure.ac: $Configure_version_string" + echo "NEWS: $NEWS_version_string" +fi + +README_version_string=`grep -m 1 Attention ../README.md | sed 's/^.*version \([^ ]\+\)\.$/\1/'` + +if [ "$Configure_version_string" != "$README_version_string" ]; then + echo "ERROR: Version number defined in configure.ac is not equal to the newest number described in README.md." + echo "configure.ac: $Configure_version_string" + echo "README.md: $README_version_string" +fi diff --git a/genqrcode/tests/rscode.c b/genqrcode/tests/rscode.c new file mode 100644 index 0000000000..2d4c47e15a --- /dev/null +++ b/genqrcode/tests/rscode.c @@ -0,0 +1,274 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon encoder. This code is taken from Phil Karn's libfec then + * editted and packed into a pair of .c and .h files. + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * (libfec is released under the GNU Lesser General Public License.) + * + * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <string.h> + +#include "rscode.h" + +/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs + * + */ +typedef unsigned char data_t; + + +/** + * Reed-Solomon codec control block + */ +struct _RS { + int mm; /* Bits per symbol */ + int nn; /* Symbols per block (= (1<<mm)-1) */ + data_t *alpha_to; /* log lookup table */ + data_t *index_of; /* Antilog lookup table */ + data_t *genpoly; /* Generator polynomial */ + int nroots; /* Number of generator roots = number of parity symbols */ + int fcr; /* First consecutive root, index form */ + int prim; /* Primitive element, index form */ + int iprim; /* prim-th root of 1, index form */ + int pad; /* Padding bytes in shortened block */ + int gfpoly; +}; + +static inline int modnn(RS *rs, int x){ + while (x >= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} + + +#define MODNN(x) modnn(rs,x) + +#define MM (rs->mm) +#define NN (rs->nn) +#define ALPHA_TO (rs->alpha_to) +#define INDEX_OF (rs->index_of) +#define GENPOLY (rs->genpoly) +#define NROOTS (rs->nroots) +#define FCR (rs->fcr) +#define PRIM (rs->prim) +#define IPRIM (rs->iprim) +#define PAD (rs->pad) +#define A0 (NN) + + +/* Initialize a Reed-Solomon codec + * symsize = symbol size, bits + * gfpoly = Field generator polynomial coefficients + * fcr = first root of RS code generator polynomial, index form + * prim = primitive element to generate polynomial roots + * nroots = RS code generator polynomial degree (number of roots) + * pad = padding bytes at front of shortened block + */ +static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) +{ + RS *rs; + + +/* Common code for intializing a Reed-Solomon control block (char or int symbols) + * Copyright 2004 Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ +//#undef NULL +//#define NULL ((void *)0) + + int i, j, sr,root,iprim; + + rs = NULL; + /* Check parameter ranges */ + if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){ + goto done; + } + + if(fcr < 0 || fcr >= (1<<symsize)) + goto done; + if(prim <= 0 || prim >= (1<<symsize)) + goto done; + if(nroots < 0 || nroots >= (1<<symsize)) + goto done; /* Can't have more roots than symbol values! */ + if(pad < 0 || pad >= ((1<<symsize) -1 - nroots)) + goto done; /* Too much padding */ + + rs = (RS *)calloc(1,sizeof(RS)); + if(rs == NULL) + goto done; + + rs->mm = symsize; + rs->nn = (1<<symsize)-1; + rs->pad = pad; + + rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); + if(rs->alpha_to == NULL){ + free(rs); + rs = NULL; + goto done; + } + rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); + if(rs->index_of == NULL){ + free(rs->alpha_to); + free(rs); + rs = NULL; + goto done; + } + + /* Generate Galois field lookup tables */ + rs->index_of[0] = A0; /* log(zero) = -inf */ + rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ + sr = 1; + for(i=0;i<rs->nn;i++){ + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if(sr & (1<<symsize)) + sr ^= gfpoly; + sr &= rs->nn; + } + if(sr != 1){ + /* field generator polynomial is not primitive! */ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + rs = NULL; + goto done; + } + + /* Form RS code generator polynomial from its roots */ + rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1)); + if(rs->genpoly == NULL){ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + rs = NULL; + goto done; + } + rs->fcr = fcr; + rs->prim = prim; + rs->nroots = nroots; + rs->gfpoly = gfpoly; + + /* Find prim-th root of 1, used in decoding */ + for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) + ; + rs->iprim = iprim / prim; + + rs->genpoly[0] = 1; + for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { + rs->genpoly[i+1] = 1; + + /* Multiply rs->genpoly[] by @**(root + x) */ + for (j = i; j > 0; j--){ + if (rs->genpoly[j] != 0) + rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; + else + rs->genpoly[j] = rs->genpoly[j-1]; + } + /* rs->genpoly[0] can never be zero */ + rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; + } + /* convert rs->genpoly[] to index form for quicker encoding */ + for (i = 0; i <= nroots; i++) + rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; + done:; + + return rs; +} + +RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) +{ + return init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad); +} + + +void free_rs_char(RS *rs) +{ + free(rs->alpha_to); + free(rs->index_of); + free(rs->genpoly); + free(rs); +} + +/* The guts of the Reed-Solomon encoder, meant to be #included + * into a function body with the following typedefs, macros and variables supplied + * according to the code parameters: + + * data_t - a typedef for the data symbol + * data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded + * data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols + * NROOTS - the number of roots in the RS code generator polynomial, + * which is the same as the number of parity symbols in a block. + Integer variable or literal. + * + * NN - the total number of symbols in a RS block. Integer variable or literal. + * PAD - the number of pad symbols in a block. Integer variable or literal. + * ALPHA_TO - The address of an array of NN elements to convert Galois field + * elements in index (log) form to polynomial form. Read only. + * INDEX_OF - The address of an array of NN elements to convert Galois field + * elements in polynomial form to index (log) form. Read only. + * MODNN - a function to reduce its argument modulo NN. May be inline or a macro. + * GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form + + * The memset() and memmove() functions are used. The appropriate header + * file declaring these functions (usually <string.h>) must be included by the calling + * program. + + * Copyright 2004, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + +#undef A0 +#define A0 (NN) /* Special reserved value encoding zero in index form */ + +void encode_rs_char(RS *rs, const data_t *data, data_t *parity) +{ + int i, j; + data_t feedback; + + memset(parity,0,NROOTS*sizeof(data_t)); + + for(i=0;i<NN-NROOTS-PAD;i++){ + feedback = INDEX_OF[data[i] ^ parity[0]]; + if(feedback != A0){ /* feedback term is non-zero */ +#ifdef UNNORMALIZED + /* This line is unnecessary when GENPOLY[NROOTS] is unity, as it must + * always be for the polynomials constructed by init_rs() + */ + feedback = MODNN(NN - GENPOLY[NROOTS] + feedback); +#endif + for(j=1;j<NROOTS;j++) + parity[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS-j])]; + } + /* Shift */ + memmove(&parity[0],&parity[1],sizeof(data_t)*(NROOTS-1)); + if(feedback != A0) + parity[NROOTS-1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])]; + else + parity[NROOTS-1] = 0; + } +} diff --git a/genqrcode/tests/rscode.h b/genqrcode/tests/rscode.h new file mode 100644 index 0000000000..d4a07c9bae --- /dev/null +++ b/genqrcode/tests/rscode.h @@ -0,0 +1,40 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon encoder. This code is taken from Phil Karn's libfec then + * editted and packed into a pair of .c and .h files. + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * (libfec is released under the GNU Lesser General Public License.) + * + * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef RSCODE_H +#define RSCODE_H + +/* + * General purpose RS codec, 8-bit symbols. + */ + +typedef struct _RS RS; + +extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad); +extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity); +extern void free_rs_char(RS *rs); + +#endif /* RSCODE_H */ diff --git a/genqrcode/tests/rsecc_decoder.c b/genqrcode/tests/rsecc_decoder.c new file mode 100644 index 0000000000..982742142b --- /dev/null +++ b/genqrcode/tests/rsecc_decoder.c @@ -0,0 +1,64 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../qrspec.h" +#include "rsecc_decoder.h" + +#define SYMBOL_SIZE (8) +#define symbols ((1 << SYMBOL_SIZE) - 1) +static const int proot = 0x11d; /* stands for x^8+x^4+x^3+x^2+1 (see pp.37 of JIS X0510:2004) */ + +/* min/max codeword length of ECC, calculated from the specification. */ +#define min_length (2) +#define max_length (30) +#define max_generatorSize (max_length) + +static unsigned char alpha[symbols + 1]; +static unsigned char aindex[symbols + 1]; + +void RSECC_decoder_init() { + int i, b; + + alpha[symbols] = 0; + aindex[0] = symbols; + + b = 1; + for(i = 0; i < symbols; i++) { + alpha[i] = (unsigned char)b; + aindex[b] = (unsigned char)i; + b <<= 1; + if(b & (symbols + 1)) { + b ^= proot; + } + b &= symbols; + } +} + +int RSECC_decoder_checkSyndrome(int dl, unsigned char *data, int el, unsigned char *ecc) +{ + int i, j; + int s; + + for(i=0; i<el; i++) { + s = data[0]; + for(j=1; j<dl; j++) { + if(s == 0) { + s = data[j]; + } else { + s = data[j] ^ alpha[(aindex[s] + i) % symbols]; + } + } + for(j=0; j<el; j++) { + if(s == 0) { + s = ecc[j]; + } else { + s = ecc[j] ^ alpha[(aindex[s] + i) % symbols]; + } + } + if(s != 0) { + return -1; + } + } + + return 0; +} diff --git a/genqrcode/tests/rsecc_decoder.h b/genqrcode/tests/rsecc_decoder.h new file mode 100644 index 0000000000..6390433872 --- /dev/null +++ b/genqrcode/tests/rsecc_decoder.h @@ -0,0 +1,7 @@ +#ifndef RSECC_DECODER_H +#define RSECC_DECODER_H + +void RSECC_decoder_init(void); +int RSECC_decoder_checkSyndrome(int dl, unsigned char *data, int el, unsigned char *ecc); + +#endif /* RSECC_DECODER_H */ diff --git a/genqrcode/tests/test_all.sh b/genqrcode/tests/test_all.sh new file mode 100755 index 0000000000..9ba040ae77 --- /dev/null +++ b/genqrcode/tests/test_all.sh @@ -0,0 +1,3 @@ +#!/bin/sh -e +. ./test_basic.sh +./test_configure.sh diff --git a/genqrcode/tests/test_basic.sh b/genqrcode/tests/test_basic.sh new file mode 100755 index 0000000000..6d90180ee3 --- /dev/null +++ b/genqrcode/tests/test_basic.sh @@ -0,0 +1,13 @@ +#!/bin/sh -e +./test_bitstream +./test_estimatebit +./test_qrencode +./test_qrinput +./test_qrspec +./test_rs +./test_split +./test_split_urls +./test_mask +./test_mqrspec +./test_mmask +./test_monkey diff --git a/genqrcode/tests/test_bitstream.c b/genqrcode/tests/test_bitstream.c new file mode 100644 index 0000000000..64b1e86d92 --- /dev/null +++ b/genqrcode/tests/test_bitstream.c @@ -0,0 +1,257 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" +#include "../bitstream.h" + +static void test_null(void) +{ + BitStream *bstream; + + testStart("Empty stream"); + bstream = BitStream_new(); + assert_zero(BitStream_size(bstream), "Size of empty BitStream is not 0.\n"); + assert_null(BitStream_toByte(bstream), "BitStream_toByte returned non-NULL.\n"); + assert_nothing(BitStream_free(NULL), "Checking BitStream_free(NULL).\n"); + testFinish(); + + BitStream_free(bstream); +} + +static void test_num(void) +{ + BitStream *bstream; + unsigned int data = 0x13579bdf; + char correct[] = "0010011010101111001101111011111"; + + testStart("New from num"); + bstream = BitStream_new(); + BitStream_appendNum(bstream, 31, data); + testEnd(cmpBin(correct, bstream)); + + BitStream_free(bstream); +} + +static void test_bytes(void) +{ + BitStream *bstream; + unsigned char data[1] = {0x3a}; + char correct[] = "00111010"; + + testStart("New from bytes"); + bstream = BitStream_new(); + BitStream_appendBytes(bstream, 1, data); + testEnd(cmpBin(correct, bstream)); + BitStream_free(bstream); +} + +static void test_appendNum(void) +{ + BitStream *bstream; + char correct[] = "10001010 11111111 11111111 00010010001101000101011001111000"; + + testStart("Append Num"); + bstream = BitStream_new(); + + BitStream_appendNum(bstream, 8, 0x0000008a); + assert_zero(ncmpBin(correct, bstream, 8), "Internal data is incorrect.\n"); + + BitStream_appendNum(bstream, 16, 0x0000ffff); + assert_zero(ncmpBin(correct, bstream, 24), "Internal data is incorrect.\n"); + + BitStream_appendNum(bstream, 32, 0x12345678); + + assert_zero(cmpBin(correct, bstream), "Internal data is incorrect.\n"); + testFinish(); + + BitStream_free(bstream); +} + +static void test_appendBytes(void) +{ + BitStream *bstream; + unsigned char data[8]; + char correct[] = "10001010111111111111111100010010001101000101011001111000"; + + testStart("Append Bytes"); + bstream = BitStream_new(); + + data[0] = 0x8a; + BitStream_appendBytes(bstream, 1, data); + assert_zero(ncmpBin(correct, bstream, 8), "Internal data is incorrect."); + + data[0] = 0xff; + data[1] = 0xff; + BitStream_appendBytes(bstream, 2, data); + assert_zero(ncmpBin(correct, bstream, 24), "Internal data is incorrect.\n"); + + data[0] = 0x12; + data[1] = 0x34; + data[2] = 0x56; + data[3] = 0x78; + BitStream_appendBytes(bstream, 4, data); + + assert_zero(cmpBin(correct, bstream), "Internal data is incorrect.\n"); + testFinish(); + + BitStream_free(bstream); +} + +static void test_toByte(void) +{ + BitStream *bstream; + unsigned char correct[] = { + 0x8a, 0xff, 0xff, 0x12, 0x34, 0x56, 0x78 + }; + unsigned char *result; + + testStart("Convert to a byte array"); + bstream = BitStream_new(); + + BitStream_appendBytes(bstream, 1, &correct[0]); + BitStream_appendBytes(bstream, 2, &correct[1]); + BitStream_appendBytes(bstream, 4, &correct[3]); + + result = BitStream_toByte(bstream); + testEnd(memcmp(correct, result, 7)); + + BitStream_free(bstream); + free(result); +} + +static void test_toByte_4bitpadding(void) +{ + BitStream *bstream; + unsigned char *result; + + testStart("Convert to a byte array"); + + bstream = BitStream_new(); + BitStream_appendNum(bstream, 4, 0xb); + result = BitStream_toByte(bstream); + assert_equal(result[0], 0xb0, "incorrect paddings\n"); + BitStream_free(bstream); + free(result); + + bstream = BitStream_new(); + BitStream_appendNum(bstream, 12, 0x335); + result = BitStream_toByte(bstream); + assert_equal(result[0], 0x33, "incorrect paddings\n"); + assert_equal(result[1], 0x50, "incorrect paddings\n"); + BitStream_free(bstream); + free(result); + + testFinish(); + +} + +static void test_size(void) +{ + BitStream *bstream; + + testStart("size check"); + bstream = BitStream_new(); + assert_equal(BitStream_size(bstream), 0, "Initialized BitStream is not 0 length"); + BitStream_appendNum(bstream, 1, 0); + assert_equal(BitStream_size(bstream), 1, "Size incorrect. (first append)"); + BitStream_appendNum(bstream, 2, 0); + assert_equal(BitStream_size(bstream), 3, "Size incorrect. (second append)"); + testFinish(); + + BitStream_free(bstream); +} + +static void test_append(void) +{ + BitStream *bs1, *bs2; + char c1[] = "00"; + char c2[] = "0011"; + char c3[] = "01111111111111111"; + char c4[] = "001101111111111111111"; + char c5[] = "0011011111111111111111111111111111"; + int ret; + + testStart("Append two BitStreams"); + + bs1 = BitStream_new(); + bs2 = BitStream_new(); + ret = BitStream_appendNum(bs1, 1, 0); + ret = BitStream_appendNum(bs2, 1, 0); + + ret = BitStream_append(bs1, bs2); + assert_zero(ret, "Failed to append."); + assert_zero(cmpBin(c1, bs1), "Internal data is incorrect."); + + ret = BitStream_appendNum(bs1, 2, 3); + assert_zero(ret, "Failed to append."); + assert_zero(cmpBin(c2, bs1), "Internal data is incorrect."); + + ret = BitStream_appendNum(bs2, 16, 65535); + assert_zero(ret, "Failed to append."); + assert_zero(cmpBin(c3, bs2), "Internal data is incorrect."); + + ret = BitStream_append(bs1, bs2); + assert_zero(ret, "Failed to append."); + assert_zero(cmpBin(c4, bs1), "Internal data is incorrect."); + + ret = BitStream_appendNum(bs1, 13, 16383); + assert_zero(ret, "Failed to append."); + assert_zero(cmpBin(c5, bs1), "Internal data is incorrect."); + + testFinish(); + + BitStream_free(bs1); + BitStream_free(bs2); +} + +static void test_newWithBits(void) +{ + BitStream *bstream; + unsigned char data[4] = {0, 1, 0, 1}; + + testStart("New with bits"); + + bstream = BitStream_newWithBits(4, data); + assert_equal(bstream->length, 4, "Internal bit length is incorrect.\n"); + assert_equal(bstream->datasize, 4, "Internal buffer size is incorrect.\n"); + assert_zero(cmpBin("0101", bstream), "Internal data is incorrect.\n"); + + testFinish(); + + BitStream_free(bstream); +} + +static void test_newWithBits_size0(void) +{ + BitStream *bstream; + + testStart("New with bits (size = 0)"); + + bstream = BitStream_newWithBits(0, NULL); + assert_equal(bstream->length, 0, "Internal bit length is incorrect.\n"); + assert_nonzero(bstream->datasize, "Internal buffer size is incorrect.\n"); + assert_nonnull(bstream->data, "Internal buffer not allocated.\n"); + + testFinish(); + + BitStream_free(bstream); +} + +int main() +{ + int tests = 11; + testInit(tests); + test_null(); + test_num(); + test_bytes(); + test_appendNum(); + test_appendBytes(); + test_toByte(); + test_toByte_4bitpadding(); + test_size(); + test_append(); + test_newWithBits(); + test_newWithBits_size0(); + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/test_configure.sh b/genqrcode/tests/test_configure.sh new file mode 100755 index 0000000000..4a301259a0 --- /dev/null +++ b/genqrcode/tests/test_configure.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +BASEDIR=.. + +CONFIG_H_IN="$BASEDIR/config.h.in" +CONFIG_H="$BASEDIR/config.h" +LIBQRENCODE_PC_IN="$BASEDIR/libqrencode.pc.in" +LIBQRENCODE_PC="$BASEDIR/libqrencode.pc" + +echo "Testing configure scripts..." + +(cd $BASEDIR; ./autogen.sh) + +# test config.h.in +grep "#undef HAVE_LIBPTHREAD" $CONFIG_H_IN > /dev/null +if test ! $? -eq 0; then + echo "HAVE_LIBPTHREAD undefined in config.h.in." + exit 1 +fi + +# test libqrencode.pc.in +grep "Libs.private: @LIBPTHREAD@" $LIBQRENCODE_PC_IN > /dev/null +if test ! $? -eq 0; then + echo "Pthread is not handled in libqrencode.pc.in." + exit 1 +fi + +# test pthread checks in configure +(cd $BASEDIR; ./configure --with-tests --enable-thread-safety > /dev/null) +grep "#define HAVE_LIBPTHREAD 1" $CONFIG_H > /dev/null +if test ! $? -eq 0; then + echo "HAVE_LIBPTHREAD undefined in config.h." + exit 1 +fi + +grep "Libs.private: -lpthread" $LIBQRENCODE_PC > /dev/null +if test ! $? -eq 0; then + echo "Pthread is not handled in libqrencode.pc." + exit 1 +fi + +(cd $BASEDIR; ./configure --with-tests --disable-thread-safety > /dev/null) +grep "#define HAVE_LIBPTHREAD 1" $CONFIG_H > /dev/null +if test ! $? -eq 1; then + echo "HAVE_LIBPTHREAD incorrectly defined in config.h." + exit 1 +fi + +grep "Libs.private: -lpthread" $LIBQRENCODE_PC > /dev/null +if test ! $? -eq 1; then + echo "Pthread is incorrectly handled in libqrencode.pc." + exit 1 +fi + +echo "All tests of configure script passed. Now reconfiguring..." + +(cd $BASEDIR; ./configure --with-tests > /dev/null) + +echo "Done." + +exit 0 diff --git a/genqrcode/tests/test_estimatebit.c b/genqrcode/tests/test_estimatebit.c new file mode 100644 index 0000000000..8392ed813a --- /dev/null +++ b/genqrcode/tests/test_estimatebit.c @@ -0,0 +1,183 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "common.h" +#include "../qrinput.h" + +static QRinput *gstream; + +static void test_numbit(void) +{ + QRinput *stream; + char num[9]="01234567"; + int bits; + + testStart("Estimation of Numeric stream (8 digits)"); + stream = QRinput_new(); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + bits = QRinput_estimateBitStreamSize(stream, 0); + testEndExp(bits == 41); + + QRinput_append(gstream, QR_MODE_NUM, 8, (unsigned char *)num); + QRinput_free(stream); +} + +static void test_numbit2(void) +{ + QRinput *stream; + char num[17]="0123456789012345"; + int bits; + + testStart("Estimation of Numeric stream (16 digits)"); + stream = QRinput_new(); + QRinput_append(stream, QR_MODE_NUM, 16, (unsigned char *)num); + bits = QRinput_estimateBitStreamSize(stream, 0); + testEndExp(bits == 68); + + QRinput_append(gstream, QR_MODE_NUM, 16, (unsigned char *)num); + QRinput_free(stream); +} + +static void test_numbit3(void) +{ + QRinput *stream; + char *num; + int bits; + + testStart("Estimation of Numeric stream (400 digits)"); + stream = QRinput_new(); + num = (char *)malloc(401); + memset(num, '1', 400); + num[400] = '\0'; + QRinput_append(stream, QR_MODE_NUM, 400, (unsigned char *)num); + bits = QRinput_estimateBitStreamSize(stream, 0); + /* 4 + 10 + 133*10 + 4 = 1348 */ + testEndExp(bits == 1348); + + QRinput_append(gstream, QR_MODE_NUM, 400, (unsigned char *)num); + QRinput_free(stream); + free(num); +} + +static void test_an(void) +{ + QRinput *stream; + char str[6]="AC-42"; + int bits; + + testStart("Estimation of Alphabet-Numeric stream (5 chars)"); + stream = QRinput_new(); + QRinput_append(stream, QR_MODE_AN, 5, (unsigned char *)str); + bits = QRinput_estimateBitStreamSize(stream, 0); + testEndExp(bits == 41); + + QRinput_append(gstream, QR_MODE_AN, 5, (unsigned char *)str); + QRinput_free(stream); +} + +static void test_8(void) +{ + QRinput *stream; + char str[9]="12345678"; + int bits; + + testStart("Estimation of 8 bit data stream (8 bytes)"); + stream = QRinput_new(); + QRinput_append(stream, QR_MODE_8, 8, (unsigned char *)str); + bits = QRinput_estimateBitStreamSize(stream, 0); + testEndExp(bits == 76); + + QRinput_append(gstream, QR_MODE_8, 8, (unsigned char *)str); + QRinput_free(stream); +} + +static void test_structure(void) +{ + QRinput *stream; + int bits; + + testStart("Estimation of a structure-append header"); + stream = QRinput_new(); + QRinput_insertStructuredAppendHeader(stream, 10, 1, 0); + bits = QRinput_estimateBitStreamSize(stream, 1); + testEndExp(bits == 20); + + QRinput_insertStructuredAppendHeader(gstream, 10, 1, 0); + QRinput_free(stream); +} + +static void test_kanji(void) +{ + int res; + + QRinput *stream; + unsigned char str[4]= {0x93, 0x5f,0xe4, 0xaa}; + int bits; + + testStart("Estimation of Kanji stream (2 chars)"); + stream = QRinput_new(); + res = QRinput_append(stream, QR_MODE_KANJI, 4, (unsigned char *)str); + if(res < 0) { + printf("Failed to add.\n"); + testEnd(1); + } else { + bits = QRinput_estimateBitStreamSize(stream, 0); + testEndExp(bits == 38); + QRinput_append(gstream, QR_MODE_KANJI, 4, (unsigned char *)str); + } + + QRinput_free(stream); +} + +static void test_mix(void) +{ + int bits; + + testStart("Estimation of Mixed stream"); + bits = QRinput_estimateBitStreamSize(gstream, 0); + testEndExp(bits == (41 + 68 + 1348 + 41 + 76 + 38 + 20)); + QRinput_free(gstream); +} + +/* Taken from JISX 0510:2018, p.23 */ +static void test_numbit1_mqr(void) +{ + QRinput *stream; + char *str = "0123456789012345"; + int bits; + + testStart("Estimation of Numeric stream for Micro QR Code (16 digits)"); + stream = QRinput_newMQR(3, QR_ECLEVEL_M); + QRinput_append(stream, QR_MODE_NUM, 16, (const unsigned char *)str); + bits = QRinput_estimateBitStreamSize(stream, QRinput_getVersion(stream)); + assert_equal(bits, 61, "Estimated bit length is wrong: %d, expected: %d.\n", bits, 61); + QRinput_free(stream); + + stream = QRinput_newMQR(4, QR_ECLEVEL_M); + QRinput_append(stream, QR_MODE_NUM, 16, (const unsigned char *)str); + bits = QRinput_estimateBitStreamSize(stream, QRinput_getVersion(stream)); + assert_equal(bits, 63, "Estimated bit length is wrong: %d, expected: %d.\n", bits, 63); + QRinput_free(stream); + + testFinish(); +} + +int main() +{ + gstream = QRinput_new(); + + int tests = 9; + testInit(tests); + test_numbit(); + test_numbit2(); + test_numbit3(); + test_an(); + test_8(); + test_kanji(); + test_structure(); + test_mix(); + test_numbit1_mqr(); + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/test_mask.c b/genqrcode/tests/test_mask.c new file mode 100644 index 0000000000..7ef7123251 --- /dev/null +++ b/genqrcode/tests/test_mask.c @@ -0,0 +1,411 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" +#include "../mask.h" +#include "../qrspec.h" +#include "decoder.h" + +static char dot[2] = {'_', '#'}; +static char *maskPatterns[8] = { + /* (i + j) mod 2 = 0 */ + "#_#_#_" + "_#_#_#" + "#_#_#_" + "_#_#_#" + "#_#_#_" + "_#_#_#", + /* i mod 2 = 0 */ + "######" + "______" + "######" + "______" + "######" + "______", + /* j mod 3 = 0 */ + "#__#__" + "#__#__" + "#__#__" + "#__#__" + "#__#__" + "#__#__", + /* (i + j) mod 3 = 0 */ + "#__#__" + "__#__#" + "_#__#_" + "#__#__" + "__#__#" + "_#__#_", + /* ((i div 2) + (j div 3)) mod 2 = 0 */ + "###___" + "###___" + "___###" + "___###" + "###___" + "###___", + /* (ij) mod 2 + (ij) mod 3 = 0 */ + "######" + "#_____" + "#__#__" + "#_#_#_" + "#__#__" + "#_____", + /* ((ij) mod 2 + (ij) mod 3) mod 2 = 0 */ + "######" + "###___" + "##_##_" + "#_#_#_" + "#_##_#" + "#___##", + /* ((ij) mod 3 + (i+j) mod 2) mod 2 = 0 */ + "#_#_#_" + "___###" + "#___##" + "_#_#_#" + "###___" + "_###__" +}; + +static void print_mask(int mask) +{ + const unsigned int w = 6; + unsigned char frame[w * w], *masked, *p; + int x, y; + + memset(frame, 0, w * w); + masked = Mask_makeMaskedFrame(w, frame, mask); + p = masked; + for(y=0; y<w; y++) { + for(x=0; x<w; x++) { + putchar(dot[*p&1]); + p++; + } + printf("\n"); + } + printf("\n"); + + free(masked); +} + +static void print_masks(void) +{ + int i; + + puts("\nPrinting mask patterns."); + for(i=0; i<8; i++) { + print_mask(i); + } +} + +static int test_mask(int mask) +{ + const int w = 6; + unsigned char frame[w * w], *masked, *p; + char *q; + int x, y; + int err = 0; + + memset(frame, 0, w * w); + masked = Mask_makeMaskedFrame(w, frame, mask); + p = masked; + q = maskPatterns[mask]; + for(y=0; y<w; y++) { + for(x=0; x<w; x++) { + if(dot[*p&1] != *q) { + err++; + } + p++; + q++; + } + } + + free(masked); + return err; +} + +static void test_masks(void) +{ + int i; + + testStart("Mask pattern checks"); + for(i=0; i<8; i++) { + assert_zero(test_mask(i), "Mask pattern %d incorrect.\n", i); + } + testFinish(); +} + +#define N1 (3) +#define N2 (3) +#define N3 (40) +#define N4 (10) + +static void test_eval(void) +{ + unsigned char *frame; + unsigned int w = 6; + int penalty; + + frame = (unsigned char *)malloc(w * w); + + testStart("Test mask evaluation (all white)"); + memset(frame, 0, w * w); + penalty = Mask_evaluateSymbol(w, frame); + testEndExp(penalty == ((N1 + 1)*w*2 + N2 * (w - 1) * (w - 1))); + + testStart("Test mask evaluation (all black)"); + memset(frame, 1, w * w); + penalty = Mask_evaluateSymbol(w, frame); + testEndExp(penalty == ((N1 + 1)*w*2 + N2 * (w - 1) * (w - 1))); + + free(frame); +} + +/* .#.#.#.#.# + * #.#.#.#.#. + * ..##..##.. + * ##..##..## + * ...###...# + * ###...###. + * ....####.. + * ####....## + * .....##### + * #####..... + */ +static void test_eval2(void) +{ + unsigned char *frame; + unsigned int w = 10; + int penalty; + unsigned int x; + + frame = (unsigned char *)malloc(w * w); + + testStart("Test mask evaluation (run length penalty check)"); + for(x=0; x<w; x++) { + frame[ x] = x & 1; + frame[w + x] = (x & 1) ^ 1; + frame[w*2 + x] = (x / 2) & 1; + frame[w*3 + x] = ((x / 2) & 1) ^ 1; + frame[w*4 + x] = (x / 3) & 1; + frame[w*5 + x] = ((x / 3) & 1) ^ 1; + frame[w*6 + x] = (x / 4) & 1; + frame[w*7 + x] = ((x / 4) & 1) ^ 1; + frame[w*8 + x] = (x / 5) & 1; + frame[w*9 + x] = ((x / 5) & 1) ^ 1; + } + penalty = Mask_evaluateSymbol(w, frame); + testEndExp(penalty == N1 * 4 + N2 * 4); + + free(frame); +} + +static void test_calcN2(void) +{ + unsigned char frame[64]; + int width; + int penalty; + int x, y; + + testStart("Test mask evaluation (2x2 block check)"); + width = 4; + for(y = 0; y < width; y++) { + for(x = 0; x < width; x++) { + frame[y * width + x] = ((x & 2) ^ (y & 2)) >> 1; + } + } + penalty = Mask_calcN2(width, frame); + assert_equal(penalty, N2 * 4, "Calculation of N2 penalty is wrong: %d, expected %d", penalty, N2 * 4); + + width = 4; + for(y = 0; y < width; y++) { + for(x = 0; x < width; x++) { + frame[y * width + x] = (((x + 1) & 2) ^ (y & 2)) >> 1; + } + } + penalty = Mask_calcN2(width, frame); + assert_equal(penalty, N2 * 2, "Calculation of N2 penalty is wrong: %d, expected %d", penalty, N2 * 2); + + width = 6; + for(y = 0; y < width; y++) { + for(x = 0; x < width; x++) { + frame[y * width + x] = (x / 3) ^ (y / 3); + } + } + penalty = Mask_calcN2(width, frame); + assert_equal(penalty, N2 * 16, "Calculation of N2 penalty is wrong: %d, expected %d", penalty, N2 * 16); + + testFinish(); +} + +static void test_eval3(void) +{ + unsigned char *frame; + int w = 15; + int penalty; + int x, y; + static unsigned char pattern[7][15] = { + {0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0}, // N3x1 + {1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1}, // N3x1 + {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1}, // N3x1 + {1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0}, // 0 + {1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1}, // N3x2 + {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0}, // N3 + (N1+1) + {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1} // (N1+1) + }; + + frame = (unsigned char *)malloc(w * w); + + testStart("Test mask evaluation (1:1:3:1:1 check)"); + + for(y=0; y<5; y++) { + for(x=0; x<w; x++) { + frame[w*y*2 + x] = pattern[y][x]; + frame[w*(y*2+1) + x] = pattern[y][x]^1; + } + } + for(x=0; x<w; x++) { + frame[w*10 + x] = x & 1; + } + for(y=5; y<7; y++) { + for(x=0; x<w; x++) { + frame[w*(y*2+1) + x] = pattern[y][x]; + frame[w*(y*2+2) + x] = pattern[y][x]^1; + } + } + /* + for(y=0; y<w; y++) { + for(x=0; x<w; x++) { + printf("%s", frame[w*y+x]?"##":".."); + } + printf("\n"); + } + */ + penalty = Mask_evaluateSymbol(w, frame); + testEndExp(penalty == N3 * 10 + (N1 + 1) * 4); + + free(frame); +} + +static void test_format(void) +{ + unsigned char *frame, *masked; + int version, mask, width, dmask; + QRecLevel level, dlevel; + QRcode *code; + int ret; + + testStart("Checking format info."); + for(version=1; version<=QRSPEC_VERSION_MAX; version++) { + frame = QRspec_newFrame(version); + width = QRspec_getWidth(version); + for(level=QR_ECLEVEL_L; level<=QR_ECLEVEL_H; level++) { + for(mask=0; mask<8; mask++) { + masked = Mask_makeMask(width, frame, mask, level); + code = QRcode_new(version, width, masked); + ret = QRcode_decodeFormat(code, &dlevel, &dmask); + assert_zero(ret, "Something wrong in format info.\n"); + assert_equal(dlevel, level, "Decoded level is wrong: %d, expected %d", dlevel, level); + assert_equal(dmask, mask, "Decoded mask is wrong: %d, expected %d", dlevel, level); + QRcode_free(code); + } + } + free(frame); + } + testFinish(); +} + +static void test_calcRunLength(void) +{ + int width = 5; + unsigned char frame[width * width]; + int runLength[width + 1]; + int i, j; + int length; + static unsigned char pattern[6][5] = { + {0, 1, 0, 1, 0}, + {1, 0, 1, 0, 1}, + {0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1}, + {0, 0, 1, 1, 1}, + {1, 1, 0, 0, 0} + }; + static int expected[6][7] = { + { 1, 1, 1, 1, 1, 0, 5}, + {-1, 1, 1, 1, 1, 1, 6}, + { 5, 0, 0, 0, 0, 0, 1}, + {-1, 5, 0, 0, 0, 0, 2}, + { 2, 3, 0, 0, 0, 0, 2}, + {-1, 2, 3, 0, 0, 0, 3} + }; + + testStart("Test runlength calc function"); + for(i=0; i<6; i++) { + length = Mask_calcRunLengthH(width, pattern[i], runLength); + assert_equal(expected[i][6], length, "Length incorrect: %d, expected %d.\n", length, expected[i][6]); + assert_zero(memcmp(runLength, expected[i], sizeof(int) * expected[i][6]), "Run length does not match: pattern %d, horizontal access.\n", i); + for(j=0; j<width; j++) { + frame[j * width] = pattern[i][j]; + } + length = Mask_calcRunLengthV(width, frame, runLength); + assert_equal(expected[i][6], length, "Length incorrect: %d, expected %d.\n", length, expected[i][6]); + assert_zero(memcmp(runLength, expected[i], sizeof(int) * expected[i][6]), "Run length does not match: pattern %d, vertical access.\n", i); + } + testFinish(); +} + +static void test_calcN1N3(void) +{ + int runLength[26]; + int length; + int penalty; + int i; + static unsigned char pattern[][16] = { + {1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, N3}, + {0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, N3}, + {1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0}, + {1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, N3}, + {1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, N3}, + {1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, N3 * 2}, + }; + + static unsigned char pattern2[][19] = { + {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, N3 + N1 + 1}, + {0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, N3 + N1 + 1}, + {1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, N1 + 1}, + {1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, N3 + N1 + 1}, + {1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, N3 + N1 + 1} + }; + + testStart("Test N3 penalty calculation"); + for(i=0; i<6; i++) { + length = Mask_calcRunLengthH(15, pattern[i], runLength); + penalty = Mask_calcN1N3(length, runLength); + assert_equal(pattern[i][15], penalty, "N3 penalty is wrong: %d, expected %d\n", penalty, pattern[i][15]); + } + for(i=0; i<5; i++) { + length = Mask_calcRunLengthH(18, pattern2[i], runLength); + penalty = Mask_calcN1N3(length, runLength); + assert_equal(pattern2[i][18], penalty, "N3 penalty is wrong: %d, expected %d\n", penalty, pattern2[i][18]); + } + testFinish(); +} + +int main(int argc, char **argv) +{ + int tests = 9; + testInit(tests); + test_masks(); + test_eval(); + test_eval2(); + test_eval3(); + test_format(); + test_calcN2(); + test_calcRunLength(); + test_calcN1N3(); + testReport(tests); + + if(argc > 1) { + print_masks(); + } + + return 0; +} diff --git a/genqrcode/tests/test_mmask.c b/genqrcode/tests/test_mmask.c new file mode 100644 index 0000000000..c6cab14a6e --- /dev/null +++ b/genqrcode/tests/test_mmask.c @@ -0,0 +1,155 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" +#include "../mmask.h" +#include "../mqrspec.h" + +static char dot[2] = {'_', '#'}; +static char *maskPatterns[4] = { + /* i mod 2 = 0 */ + "######" + "______" + "######" + "______" + "######" + "______", + /* ((i div 2) + (j div 3)) mod 2 = 0 */ + "###___" + "###___" + "___###" + "___###" + "###___" + "###___", + /* ((ij) mod 2 + (ij) mod 3) mod 2 = 0 */ + "######" + "###___" + "##_##_" + "#_#_#_" + "#_##_#" + "#___##", + /* ((ij) mod 3 + (i+j) mod 2) mod 2 = 0 */ + "#_#_#_" + "___###" + "#___##" + "_#_#_#" + "###___" + "_###__" +}; + +static void print_mask(int mask) +{ + const int w = 6; + unsigned char frame[w * w], *masked, *p; + int x, y; + + memset(frame, 0, w * w); + masked = MMask_makeMaskedFrame(w, frame, mask); + p = masked; + for(y=0; y<w; y++) { + for(x=0; x<w; x++) { + putchar(dot[*p&1]); + p++; + } + printf("\n"); + } + printf("\n"); + + free(masked); +} + +static void print_masks(void) +{ + int i; + + puts("\nPrinting mask patterns."); + for(i=0; i<4; i++) { + print_mask(i); + } +} + +static int test_mask(int mask) +{ + const int w = 6; + unsigned char frame[w * w], *masked, *p; + char *q; + int x, y; + int err = 0; + + memset(frame, 0, w * w); + masked = MMask_makeMaskedFrame(w, frame, mask); + p = masked; + q = maskPatterns[mask]; + for(y=0; y<w; y++) { + for(x=0; x<w; x++) { + if(dot[*p&1] != *q) { + err++; + } + p++; + q++; + } + } + + free(masked); + return err; +} + +static void test_masks(void) +{ + int i; + + testStart("Mask pattern checks"); + for(i=0; i<4; i++) { + assert_zero(test_mask(i), "Mask pattern %d incorrect.\n", i); + } + testFinish(); +} + +static void test_maskEvaluation(void) +{ + static const int w = 11; + unsigned char pattern[w * w]; + int i, score; + + memset(pattern, 0, w * w); + + testStart("Test mask evaluation"); + score = MMask_evaluateSymbol(w, pattern); + assert_equal(score, 0, "Mask score caluculation is incorrect. (score=%d (%d expected)\n", score, 0); + + for(i=0; i<w; i++) { + pattern[(w-1) * w + i] = 1; + } + score = MMask_evaluateSymbol(w, pattern); + assert_equal(score, 16 + w - 1, "Mask score caluculation is incorrect. (score=%d) (%d expected)\n", score, 16 + w - 1); + + for(i=0; i<w; i++) { + pattern[(w-1) * w + i] = 0; + pattern[i * w + w - 1] = 1; + } + score = MMask_evaluateSymbol(w, pattern); + assert_equal(score, 16 + w - 1, "Mask score caluculation is incorrect. (score=%d) (%d expected)\n", score, 16 + w - 1); + + for(i=0; i<w; i++) { + pattern[(w-1) * w + i] = 1; + pattern[i * w + w - 1] = 1; + } + score = MMask_evaluateSymbol(w, pattern); + assert_equal(score, 16 * (w - 1) + w - 1, "Mask score caluculation is incorrect. (score=%d) (%d expected)\n", score, 16 * (w - 1) + w - 1); + + testFinish(); +} + +int main(int argc, char **argv) +{ + int tests = 2; + testInit(tests); + test_masks(); + test_maskEvaluation(); + testReport(tests); + + if(argc > 1) { + print_masks(); + } + + return 0; +} diff --git a/genqrcode/tests/test_monkey.c b/genqrcode/tests/test_monkey.c new file mode 100644 index 0000000000..f50fdca1dd --- /dev/null +++ b/genqrcode/tests/test_monkey.c @@ -0,0 +1,582 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "common.h" +#include "../qrinput.h" +#include "../split.h" +#include "../qrspec.h" +#include "decoder.h" + +#define MAX_LENGTH 7091 +static unsigned char data[MAX_LENGTH]; +static unsigned char check[MAX_LENGTH]; + +static const char *AN = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + +#define drand(__scale__) ((__scale__) * (double)rand() / ((double)RAND_MAX + 1.0)) + +static int fill8bitString(void) +{ + int len, i; + + len = 1 + (int)drand((MAX_LENGTH - 2)); + for(i=0; i<len; i++) { + data[i] = (unsigned char)drand(255) + 1; + } + data[len] = '\0'; + + return len; +} + +static int fill8bitData(void) +{ + int len, i; + + len = 1 + (int)drand((MAX_LENGTH - 2)); + for(i=0; i<len; i++) { + data[i] = (unsigned char)drand(256); + } + data[len] = '\0'; + + return len; +} + +static int fillANData(void) +{ + int len, i; + + len = 1 + (int)drand((MAX_LENGTH - 2)); + for(i=0; i<len; i++) { + data[i] = AN[(int)drand(45)]; + } + data[len] = '\0'; + + return len; +} + +static void test_encode_an(int num) +{ + int ret; + int len; + len = fillANData(); + QRcode *qrcode; + QRdata *qrdata; + FILE *fp; + char buf[256]; + + qrcode = QRcode_encodeString((char *)data, 0, num % 4, QR_MODE_8, num % 2); + if(qrcode == NULL) { + if(errno == ERANGE) return; + perror("test_encode_an aborted at QRcode_encodeString():"); + printf("Length: %d\n", len); + printf("Level: %d\n", num % 4); + return; + } + qrdata = QRcode_decode(qrcode); + if(qrdata == NULL) { + printf("#%d: Failed to decode this code.\n", num); + QRcode_free(qrcode); + return; + } + if(qrdata->size != len) { + printf("#%d: length mismatched (orig: %d, decoded: %d)\n", num, len, qrdata->size); + } + ret = memcmp(qrdata->data, data, len); + if(ret != 0) { + unsigned char *frame, *p; + unsigned int x; + int y,c; + int dataLength, eccLength; + QRinput *input; + QRcode *origcode; + BitStream *bstream; + int spec[5]; + + printf("#%d: data mismatched.\n", num); + printf("Version: %d\n", qrcode->version); + QRspec_getEccSpec(qrcode->version, num%4, spec); + printf("DataLength: %d\n", QRspec_rsDataLength(spec)); + printf("BlockNum1: %d\n", QRspec_rsBlockNum1(spec)); + printf("BlockNum: %d\n", QRspec_rsBlockNum(spec)); + printf("DataCodes1: %d\n", QRspec_rsDataCodes1(spec)); + + snprintf(buf, 256, "monkey-orig-%d.dat", num); + fp = fopen(buf, "w"); + fputs((char *)data, fp); + fclose(fp); + + snprintf(buf, 256, "monkey-result-%d.dat", num); + fp = fopen(buf, "w"); + fputs((char *)qrdata->data, fp); + fclose(fp); + + snprintf(buf, 256, "monkey-result-unmasked-%d.dat", num); + fp = fopen(buf, "w"); + frame = QRcode_unmask(qrcode); + p = frame; + for(y=0; y<qrcode->width; y++) { + for(x=0; x<qrcode->width; x++) { + fputc((*p&1)?'1':'0', fp); + p++; + } + fputc('\n', fp); + } + fclose(fp); + free(frame); + + snprintf(buf, 256, "monkey-orig-unmasked-%d.dat", num); + fp = fopen(buf, "w"); + input = QRinput_new2(0, num % 4); + Split_splitStringToQRinput((char *)data, input, QR_MODE_8, num % 2); + origcode = QRcode_encodeMask(input, -2); + p = origcode->data; + for(y=0; y<origcode->width; y++) { + for(x=0; x<origcode->width; x++) { + fputc((*p&1)?'1':'0', fp); + p++; + } + fputc('\n', fp); + } + fclose(fp); + QRcode_free(origcode); + + snprintf(buf, 256, "monkey-orig-bits-%d.dat", num); + fp = fopen(buf, "w"); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + c = 0; + for(x=0; x<bstream->length; x++) { + fputc((bstream->data[x]&1)?'1':'0', fp); + if((x & 7) == 7) { + fputc(' ', fp); + c++; + } + if((x & 63) == 63) { + fprintf(fp, "%d\n", c); + } + } + fclose(fp); + QRinput_free(input); + BitStream_free(bstream); + + snprintf(buf, 256, "monkey-result-bits-%d.dat", num); + fp = fopen(buf, "w"); + bstream = QRcode_extractBits(qrcode, &dataLength, &eccLength); + y = bstream->length; + p = bstream->data; + c = 0; + for(x=0; x<y; x++) { + fputc((p[x]&1)?'1':'0', fp); + if((x & 7) == 7) { + fputc(' ', fp); + c++; + } + if((x & 63) == 63) { + fprintf(fp, "%d\n", c); + } + } + fclose(fp); + BitStream_free(bstream); + } + QRdata_free(qrdata); + QRcode_free(qrcode); +} + +static void monkey_encode_an(int loop) +{ + int i; + + testStart("Monkey test: QRcode_encodeString() - AlphaNumeric string."); + srand(0); + for(i=0; i<loop; i++) { + test_encode_an(i); + } + testEnd(0); +} + + +static void test_split_an(int num) +{ + QRinput *input; + QRinput_List *list; + int len, i, ret; + + len = fillANData(); + + input = QRinput_new2(0, QR_ECLEVEL_L); + if(input == NULL) { + perror("test_split_an aborted at QRinput_new2():"); + return; + } + ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_8, 1); + if(ret < 0) { + perror("test_split_an aborted at Split_splitStringToQRinput():"); + QRinput_free(input); + return; + } + list = input->head; + i = 0; + while(list != NULL) { + memcpy(check + i, list->data, list->size); + i += list->size; + list = list->next; + } + if(i != len) { + printf("#%d: length is not correct. (%d should be %d)\n", num, i, len); + } + + check[i] = '\0'; + ret = memcmp(data, check, len); + if(ret != 0) { + printf("#%d: data mismatched.\n", num); + list = input->head; + i = 0; + while(list != NULL) { + ret = memcmp(data + i, list->data, list->size); + printf("wrong chunk:\n"); + printf(" position: %d\n", i); + printf(" mode : %d\n", list->mode); + printf(" size : %d\n", list->size); + printf(" data : %.*s\n", list->size, list->data); + i += list->size; + list = list->next; + } + exit(1); + } + QRinput_free(input); +} + +static void monkey_split_an(int loop) +{ + int i; + + testStart("Monkey test: Split_splitStringToQRinput() - AlphaNumeric string."); + srand(0); + for(i=0; i<loop; i++) { + test_split_an(i); + } + testEnd(0); +} + +static void test_encode_8(int num) +{ + QRcode *qrcode; + QRdata *qrdata; + int len, ret; + + len = fill8bitData(); + + qrcode = QRcode_encodeData(len, data, 0, num % 4); + if(qrcode == NULL) { + if(errno == ERANGE) return; + perror("test_encdoe_8 aborted at QRcode_encodeData():"); + return; + } + qrdata = QRcode_decode(qrcode); + if(qrdata == NULL) { + printf("#%d: Failed to decode this code.\n", num); + QRcode_free(qrcode); + return; + } + if(qrdata->size != len) { + printf("#%d: length mismatched (orig: %d, decoded: %d)\n", num, len, qrdata->size); + } + ret = memcmp(qrdata->data, data, len); + if(ret != 0) { + printf("#%d: data mismatched.\n", num); + } + QRdata_free(qrdata); + QRcode_free(qrcode); +} + +static void monkey_encode_8(int loop) +{ + int i; + + testStart("Monkey test: QRcode_encodeData() - 8bit char string."); + srand(0); + for(i=0; i<loop; i++) { + test_encode_8(i); + } + testEnd(0); +} + +static void test_split_8(int num) +{ + QRinput *input; + QRinput_List *list; + int len, i, ret; + + len = fill8bitString(); + + input = QRinput_new2(0, QR_ECLEVEL_L); + if(input == NULL) { + perror("test_split_8 aborted at QRinput_new2():"); + return; + } + ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_8, 1); + if(ret < 0) { + perror("test_split_8 aborted at Split_splitStringToQRinput():"); + QRinput_free(input); + return; + } + list = input->head; + i = 0; + while(list != NULL) { + memcpy(check + i, list->data, list->size); + i += list->size; + list = list->next; + } + if(i != len) { + printf("#%d: length is not correct. (%d should be %d)\n", num, i, len); + } + + check[i] = '\0'; + ret = memcmp(data, check, len); + if(ret != 0) { + printf("#%d: data mismatched.\n", num); + list = input->head; + i = 0; + while(list != NULL) { + ret = memcmp(data + i, list->data, list->size); + printf("wrong chunk:\n"); + printf(" position: %d\n", i); + printf(" mode : %d\n", list->mode); + printf(" size : %d\n", list->size); + printf(" data : %.*s\n", list->size, list->data); + i += list->size; + list = list->next; + } + exit(1); + } + QRinput_free(input); +} + +static void monkey_split_8(int loop) +{ + int i; + + testStart("Monkey test: Split_splitStringToQRinput() - 8bit char string."); + srand(0); + for(i=0; i<loop; i++) { + test_split_8(i); + } + testEnd(0); +} + +static void test_encode_kanji(int num) +{ + QRcode *qrcode; + QRdata *qrdata; + int len, ret; + + len = fill8bitString(); + + qrcode = QRcode_encodeString((char *)data, 0, num % 4, QR_MODE_8, 1); + if(qrcode == NULL) { + if(errno == ERANGE) return; + perror("test_encdoe_kanji aborted at QRcode_encodeString():"); + return; + } + qrdata = QRcode_decode(qrcode); + if(qrdata == NULL) { + printf("#%d: Failed to decode this code.\n", num); + QRcode_free(qrcode); + return; + } + if(qrdata->size != len) { + printf("#%d: length mismatched (orig: %d, decoded: %d)\n", num, len, qrdata->size); + } + ret = memcmp(qrdata->data, data, len); + if(ret != 0) { + printf("#%d: data mismatched.\n", num); + } + QRdata_free(qrdata); + QRcode_free(qrcode); +} + +static void monkey_encode_kanji(int loop) +{ + int i; + + testStart("Monkey test: QRcode_encodeString() - kanji string."); + srand(0); + for(i=0; i<loop; i++) { + test_encode_kanji(i); + } + testEnd(0); +} + +static void test_split_kanji(int num) +{ + QRinput *input; + QRinput_List *list; + int len, i, ret; + + len = fill8bitString(); + + input = QRinput_new2(0, QR_ECLEVEL_L); + if(input == NULL) { + perror("test_split_kanji aborted at QRinput_new2():"); + return; + } + ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_KANJI, 1); + if(ret < 0) { + perror("test_split_kanji aborted at Split_splitStringToQRinput():"); + QRinput_free(input); + return; + } + list = input->head; + i = 0; + while(list != NULL) { + memcpy(check + i, list->data, list->size); + i += list->size; + list = list->next; + } + if(i != len) { + printf("#%d: length is not correct. (%d should be %d)\n", num, i, len); + } + + check[i] = '\0'; + ret = memcmp(data, check, len); + if(ret != 0) { + printf("#%d: data mismatched.\n", num); + list = input->head; + i = 0; + while(list != NULL) { + ret = memcmp(data + i, list->data, list->size); + printf("wrong chunk:\n"); + printf(" position: %d\n", i); + printf(" mode : %d\n", list->mode); + printf(" size : %d\n", list->size); + printf(" data : %.*s\n", list->size, list->data); + i += list->size; + list = list->next; + } + exit(1); + } + QRinput_free(input); +} + +static void monkey_split_kanji(int loop) +{ + int i; + + testStart("Monkey test: Split_splitStringToQRinput() - kanji string."); + srand(0); + for(i=0; i<loop; i++) { + test_split_kanji(i); + } + testEnd(0); +} + +static void test_split_structure(int num) +{ + QRinput *input; + QRinput_Struct *s; + QRcode_List *codes, *list; + QRinput_InputList *il; + int version; + QRecLevel level; + int c, i, ret; + + version = (int)drand(40) + 1; + level = (QRecLevel)drand(4); + + fill8bitString(); + + input = QRinput_new2(version, level); + if(input == NULL) { + perror("test_split_structure aborted at QRinput_new2():"); + return; + } + ret = Split_splitStringToQRinput((char *)data, input, QR_MODE_KANJI, 1); + if(ret < 0) { + perror("test_split_structure aborted at Split_splitStringToQRinput():"); + QRinput_free(input); + return; + } + s = QRinput_splitQRinputToStruct(input); + if(s == NULL) { + if(errno != 0 && errno != ERANGE) { + perror("test_split_structure aborted at QRinput_splitQRinputToStruct():"); + } + QRinput_free(input); + return; + } + il = s->head; + i = 0; + while(il != NULL) { + if(il->input->version != version) { + printf("Test: version %d, level %c\n", version, levelChar[level]); + printf("wrong version number.\n"); + printQRinputInfo(il->input); + exit(1); + } + i++; + il = il->next; + } + codes = QRcode_encodeInputStructured(s); + if(codes == NULL) { + perror("test_split_structure aborted at QRcode_encodeInputStructured():"); + QRinput_free(input); + QRinput_Struct_free(s); + return; + } + list = codes; + il = s->head; + c = 0; + while(list != NULL) { + if(list->code->version != version) { + printf("#%d: data mismatched.\n", num); + printf("Test: version %d, level %c\n", version, levelChar[level]); + printf("code #%d\n", c); + printf("Version mismatch: %d should be %d\n", list->code->version, version); + printf("max bits: %d\n", QRspec_getDataLength(version, level) * 8 - 20); + printQRinputInfo(il->input); + printQRinput(input); + exit(1); + } + list = list->next; + il = il->next; + c++; + } + + QRinput_free(input); + QRinput_Struct_free(s); + QRcode_List_free(codes); + + return; +} + +static void monkey_split_structure(int loop) +{ + int i; + + testStart("Monkey test: QRinput_splitQRinputToStruct."); + srand(0); + for(i=0; i<loop; i++) { + test_split_structure(i); + } + testEnd(0); +} + +int main(int argc, char **argv) +{ + int loop = 1000; + if(argc == 2) { + loop = atoi(argv[1]); + } + int tests = 7; + testInit(tests); + monkey_split_an(loop); + monkey_encode_an(loop); + monkey_split_8(loop); + monkey_encode_8(loop); + monkey_split_kanji(loop); + monkey_encode_kanji(loop); + monkey_split_structure(loop); + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/test_mqrspec.c b/genqrcode/tests/test_mqrspec.c new file mode 100644 index 0000000000..3a4b18950b --- /dev/null +++ b/genqrcode/tests/test_mqrspec.c @@ -0,0 +1,181 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" +#include "../mqrspec.h" + +static unsigned char v4frame[] = { + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc0,0x91,0x90,0x91,0x90,0x91,0x90,0x91,0x90,0x91, + 0xc1,0xc0,0xc0,0xc0,0xc0,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xc1,0xc0,0xc1,0xc1,0xc1,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xc1,0xc0,0xc1,0xc1,0xc1,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xc1,0xc0,0xc1,0xc1,0xc1,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xc1,0xc0,0xc0,0xc0,0xc0,0xc0,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x91,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static void test_newFrame(void) +{ + int width, i, y; + unsigned char *frame; + + testStart("Test empty frames"); + for(i=1; i<MQRSPEC_VERSION_MAX; i++) { + frame = MQRspec_newFrame(i); + width = MQRspec_getWidth(i); + for(y=0; y<width; y++) { + assert_zero(memcmp(&frame[y * width], &v4frame[y * MQRSPEC_WIDTH_MAX], width), "Mismatch found in version %d, line %d.\n", i, y); + } + free(frame); + } + testFinish(); +} + +static void test_newframe_invalid(void) +{ + unsigned char *frame; + + testStart("Checking MQRspec_newFrame with invalid version."); + frame = MQRspec_newFrame(0); + assert_null(frame, "MQRspec_newFrame(0) returns non-NULL."); + frame = MQRspec_newFrame(MQRSPEC_VERSION_MAX+1); + assert_null(frame, "MQRspec_newFrame(0) returns non-NULL."); + testFinish(); +} + +/* See Table 10 (pp.115) of Appendix 1, JIS X0510:2004 */ +static unsigned int calcFormatInfo(int type, int mask) +{ + unsigned int data, ecc, b, code; + int i, c; + + data = (type << 12) | (mask << 10); + ecc = data; + b = 1 << 14; + for(i=0; b != 0; i++) { + if(ecc & b) break; + b = b >> 1; + } + c = 4 - i; + code = 0x537 << c ; //10100110111 + b = 1 << (10 + c); + for(i=0; i<=c; i++) { + if(b & ecc) { + ecc ^= code; + } + code = code >> 1; + b = b >> 1; + } + + return (data | ecc) ^ 0x4445; +} + +/* See Table 10 of Appendix 1. (pp.115) */ +static const int typeTable[4][3] = { + { 0, -1, -1}, + { 1, 2, -1}, + { 3, 4, -1}, + { 5, 6, 7} +}; + +static void test_format(void) +{ + unsigned int format; + int version, l, mask; + int type; + int err = 0; + + testStart("Format info test"); + for(version=1; version<=MQRSPEC_VERSION_MAX; version++) { + for(l=QR_ECLEVEL_L; l<=QR_ECLEVEL_Q; l++) { + for(mask=0; mask<4; mask++) { + format = MQRspec_getFormatInfo(mask, version, (QRecLevel)l); + type = typeTable[version - 1][l]; + if(type == -1) { + if(format != 0) { + printf("Error in version %d, level %d, mask %d\n", + version, l, mask); + err++; + } + } else { + if(format != calcFormatInfo(type, mask)) { + printf("Error in version %d, level %d, mask %d\n", + version, l, mask); + err++; + } + } + } + } + } + testEnd(err); +} + +static void print_format(void) +{ + unsigned int format; + int i, j; + + puts("\nPrinting hex strings of format information."); + for(i=0; i<4; i++) { + for(j=0; j<8; j++) { + format = calcFormatInfo(j, i); + printf("0x%04x, ", format); + } + printf("\n"); + } +} + +/** + * See Table 7 of Appendix 1. + */ +static int datalen[4][3] = { + { 20, 0, 0}, + { 40, 32, 0}, + { 84, 68, 0}, + {128, 112, 80}, +}; + +static void test_dataLength(void) +{ + int v, l; + int bits; + int err = 0; + + testStart("Test dataLength"); + for(v=0; v<4; v++) { + for(l=0; l<3; l++) { + bits = MQRspec_getDataLengthBit(v+1, (QRecLevel)l); + if(bits != datalen[v][l]) { + printf("Error in version %d, level %d.\n", v, l); + err++; + } + } + } + testEnd(err); +} + +int main(int argc, char **argv) +{ + int tests = 4; + testInit(tests); + test_newFrame(); + test_newframe_invalid(); + test_format(); + test_dataLength(); + testReport(tests); + + if(argc > 1) { + print_format(); + } + + return 0; +} diff --git a/genqrcode/tests/test_qrenc.sh b/genqrcode/tests/test_qrenc.sh new file mode 100755 index 0000000000..8c39c6a9aa --- /dev/null +++ b/genqrcode/tests/test_qrenc.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +COMMAND=../qrencode +VALGRIND_COMMAND="libtool --mode=execute valgrind" +VALGRIND_OPTIONS="--leak-check=full --show-reachable=yes" + +if [ "x$1" = 'xvalgrind' ]; then + COMMAND="$VALGRIND_COMMAND $VALGRIND_OPTIONS $COMMAND" +fi + +repeatchar() +{ + printf %${2}s | tr ' ' ${1} +} + +test_command_success() +{ + repeatchar ${1} ${2} | $COMMAND -o - -l L ${3} > /dev/null + if [ $? -ne 0 ]; then + echo "Failed to encode $fn.txt" + exit 1 + fi +} + +test_command_fail() +{ + repeatchar ${1} ${2} | $COMMAND -o - -l L ${3} > /dev/null + if [ $? -eq 0 ]; then + echo "Unexpectedly successed to encode '${1}'x'${2}' with '${3}'." + exit 1 + else + echo "^^^this is the expected error. Everything OK." + fi +} + +test_command_success '1' 7089 +test_command_success 'A' 4296 +test_command_success 'a' 2953 +test_command_success '\211' 3634 '-k' + +test_command_fail '1' 7090 +test_command_fail 'A' 4297 +test_command_fail 'a' 2954 +test_command_fail '\211' 3636 '-k' +test_command_fail '1' 15000 diff --git a/genqrcode/tests/test_qrencode.c b/genqrcode/tests/test_qrencode.c new file mode 100644 index 0000000000..589b9b18ef --- /dev/null +++ b/genqrcode/tests/test_qrencode.c @@ -0,0 +1,1073 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "common.h" +#include "../qrencode_inner.h" +#include "../qrspec.h" +#include "../mqrspec.h" +#include "../qrinput.h" +#include "../mask.h" +#include "../rsecc.h" +#include "../split.h" +#include "decoder.h" + +static const char decodeAnTable[45] = { + '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', ' ', '$', '%', '*', + '+', '-', '.', '/', ':' +}; + +typedef struct { + char *str; + int version; + QRecLevel level; + QRencodeMode hint; + int casesensitive; +} TestString; +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) + +#define drand(__scale__) ((__scale__) * (double)rand() / ((double)RAND_MAX + 1.0)) + +static void test_qrraw_new(void) +{ + int i; + QRinput *stream; + char num[9] = "01234567"; + QRRawCode *raw; + + testStart("Test QRraw_new()"); + stream = QRinput_new(); + QRinput_setVersion(stream, 10); + QRinput_setErrorCorrectionLevel(stream, QR_ECLEVEL_Q); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + + raw = QRraw_new(stream); + assert_nonnull(raw, "Failed QRraw_new().\n"); + assert_zero(raw->count, "QRraw.count = %d != 0\n", raw->count); + assert_equal(raw->version, 10, "QRraw.version was not as expected. (%d)\n", raw->version); + assert_equal(raw->dataLength, 19 * 6 + 20 * 2, "QRraw.dataLength was not as expected.\n"); + assert_equal(raw->eccLength, 24 * 8, "QRraw.eccLength was not as expected.\n"); + assert_equal(raw->b1, 6, "QRraw.b1 was not as expected.\n"); + assert_equal(raw->blocks, 8, "QRraw.blocks was not as expected.\n"); + + for(i=0; i<raw->b1; i++) { + assert_equal(raw->rsblock[i].dataLength, 19, "QRraw.rsblock[%d].dataLength was not as expected. (%d)\n", i, raw->rsblock[i].dataLength); + } + for(i=raw->b1; i<raw->blocks; i++) { + assert_equal(raw->rsblock[i].dataLength, 20, "QRraw.rsblock[%d].dataLength was not as expected. (%d)\n", i, raw->rsblock[i].dataLength); + } + for(i=0; i<raw->blocks; i++) { + assert_equal(raw->rsblock[i].eccLength, 24, "QRraw.rsblock[%d].eccLength was not as expected. (%d)\n", i, raw->rsblock[i].eccLength); + } + + QRinput_free(stream); + QRraw_free(raw); + testFinish(); +} + +static void test_iterate() +{ + int i; + QRinput *stream; + char num[9] = "01234567"; + unsigned char *data; + QRRawCode *raw; + int err = 0; + + testStart("Test getCode (1-L)"); + stream = QRinput_new(); + QRinput_setVersion(stream, 1); + QRinput_setErrorCorrectionLevel(stream, QR_ECLEVEL_L); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + + raw = QRraw_new(stream); + data = raw->datacode; + for(i=0; i<raw->dataLength; i++) { + if(data[i] != QRraw_getCode(raw)) { + err++; + } + } + + QRinput_free(stream); + QRraw_free(raw); + testEnd(err); +} + +static void test_iterate2() +{ + int i; + QRinput *stream; + char num[9] = "01234567"; + QRRawCode *raw; + int err = 0; + unsigned char correct[] = { + 0x10, 0x11, 0xec, 0xec, 0x20, 0xec, 0x11, 0x11, + 0x0c, 0x11, 0xec, 0xec, 0x56, 0xec, 0x11, 0x11, + 0x61, 0x11, 0xec, 0xec, 0x80, 0xec, 0x11, 0x11, + 0xec, 0x11, 0xec, 0xec, 0x11, 0xec, 0x11, 0x11, + 0xec, 0x11, 0xec, 0xec, 0x11, 0xec, 0x11, 0x11, + 0xec, 0x11, 0xec, 0xec, 0x11, 0x11, + 0x5c, 0xde, 0x68, 0x68, 0x4d, 0xb3, 0xdb, 0xdb, + 0xd5, 0x14, 0xe1, 0xe1, 0x5b, 0x2a, 0x1f, 0x1f, + 0x49, 0xc4, 0x78, 0x78, 0xf7, 0xe0, 0x5b, 0x5b, + 0xc3, 0xa7, 0xc1, 0xc1, 0x5d, 0x9a, 0xea, 0xea, + 0x48, 0xad, 0x9d, 0x9d, 0x58, 0xb3, 0x3f, 0x3f, + 0x10, 0xdb, 0xbf, 0xbf, 0xeb, 0xec, 0x05, 0x05, + 0x98, 0x35, 0x83, 0x83, 0xa9, 0x95, 0xa6, 0xa6, + 0xea, 0x7b, 0x8d, 0x8d, 0x04, 0x3c, 0x08, 0x08, + 0x64, 0xce, 0x3e, 0x3e, 0x4d, 0x9b, 0x30, 0x30, + 0x4e, 0x65, 0xd6, 0xd6, 0xe4, 0x53, 0x2c, 0x2c, + 0x46, 0x1d, 0x2e, 0x2e, 0x29, 0x16, 0x27, 0x27 + }; + + testStart("Test getCode (5-H)"); + stream = QRinput_new(); + QRinput_setVersion(stream, 5); + QRinput_setErrorCorrectionLevel(stream, QR_ECLEVEL_H); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + + raw = QRraw_new(stream); + for(i=0; i<raw->dataLength; i++) { + if(correct[i] != QRraw_getCode(raw)) { + err++; + } + } + + QRinput_free(stream); + QRraw_free(raw); + testEnd(err); +} + +static void print_filler(void) +{ + int width; + int version = 7; + unsigned char *frame; + + puts("\nPrinting debug info of FrameFiller."); + width = QRspec_getWidth(version); + frame = FrameFiller_test(version); + if(frame == NULL) abort(); + + printFrame(width, frame); + free(frame); +} + +static void test_filler(void) +{ + unsigned char *frame; + int i, j, w, e, length; + + testStart("Frame filler test"); + for(i=1; i<=QRSPEC_VERSION_MAX; i++) { + length = QRspec_getDataLength(i, QR_ECLEVEL_L) * 8 + + QRspec_getECCLength(i, QR_ECLEVEL_L) * 8 + + QRspec_getRemainder(i); + frame = FrameFiller_test(i); + if(frame == NULL) { + assert_nonnull(frame, "Something wrong in version %d\n", i); + } else { + w = QRspec_getWidth(i); + e = 0; + for(j=0; j<w*w; j++) { + if(frame[j] == 0) e++; + } + assert_zero(e, "Not filled bit is found. (%d,%d)\n", j%w,j/w); + e = w * (w - 9 - ((i > 6)?3:0)); + assert_equal(frame[e], (unsigned char)((length - 1) & 127) | 0x80, + "Number of cell does not match.\n"); + free(frame); + } + } + testFinish(); +} + +static void print_fillerMQR(void) +{ + int width; + int version = 3; + unsigned char *frame; + + puts("\nPrinting debug info of FrameFiller for Micro QR."); + for(version = 1; version <= MQRSPEC_VERSION_MAX; version++) { + width = MQRspec_getWidth(version); + frame = FrameFiller_testMQR(version); + if(frame == NULL) abort(); + + printFrame(width, frame); + } +} + +static void test_fillerMQR(void) +{ + unsigned char *frame; + int i, j, w, e, length; + + testStart("Micro QR Code Frame filler test"); + for(i=1; i<=MQRSPEC_VERSION_MAX; i++) { + length = MQRspec_getDataLengthBit(i, QR_ECLEVEL_L) + + MQRspec_getECCLength(i, QR_ECLEVEL_L) * 8; + frame = FrameFiller_testMQR(i); + if(frame == NULL) { + assert_nonnull(frame, "Something wrong in version %d\n", i); + } else { + w = MQRspec_getWidth(i); + e = 0; + for(j=0; j<w*w; j++) { + if(frame[j] == 0) e++; + } + assert_zero(e, "Not filled bit is found. (%d,%d)\n", j%w,j/w); + if(i & 1) { + e = w * 9 + 1; + } else { + e = w * (w - 1) + 1; + } + assert_equal(frame[e], (unsigned char)((length - 1) & 127) | 0x80, + "Number of cell does not match in version %d.\n", i); + free(frame); + } + } + testFinish(); +} + +static void test_format(void) +{ + unsigned char *frame; + unsigned int format; + int width; + int i; + unsigned int decode; + int blacks, b1 = 0, b2 = 0; + + testStart("Test format information(level L,mask 0)"); + width = QRspec_getWidth(1); + frame = QRspec_newFrame(1); + if(frame == NULL) goto ABORT; + format = QRspec_getFormatInfo(1, QR_ECLEVEL_L); + blacks = Mask_writeFormatInformation(width, frame, 1, QR_ECLEVEL_L); + decode = 0; + for(i=0; i<15; i++) { + if((1<<i) & format) b2 += 2; + } + for(i=0; i<8; i++) { + decode = decode << 1; + decode |= frame[width * 8 + i + (i > 5)] & 1; + if(decode & 1) b1++; + } + for(i=0; i<7; i++) { + decode = decode << 1; + decode |= frame[width * ((6 - i) + (i < 1)) + 8] & 1; + if(decode & 1) b1++; + } + if(decode != format) { + printf("Upper-left format information is invalid.\n"); + printf("%08x, %08x\n", format, decode); + testEnd(1); + return; + } + decode = 0; + for(i=0; i<7; i++) { + decode = decode << 1; + decode |= frame[width * (width - 1 - i) + 8] & 1; + if(decode & 1) b1++; + } + for(i=0; i<8; i++) { + decode = decode << 1; + decode |= frame[width * 8 + width - 8 + i] & 1; + if(decode & 1) b1++; + } + if(decode != format) { + printf("Bottom and right format information is invalid.\n"); + printf("%08x, %08x\n", format, decode); + testEnd(1); + return; + } + + if(b2 != blacks || b1 != b2) { + printf("Number of dark modules is incorrect.\n"); + printf("Return value: %d, dark modules in frame: %d, should be: %d\n", blacks, b1, b2); + testEnd(1); + return; + } + + free(frame); + +ABORT: + testEnd(0); +} + +unsigned int m1pat[8][21] = { + {0x1fc77f, 0x105c41, 0x174c5d, 0x174b5d, 0x175b5d, 0x104241, 0x1fd57f, + 0x000000, 0x154512, 0x1a16a2, 0x0376ee, 0x19abb2, 0x04eee1, 0x001442, + 0x1fc111, 0x10444b, 0x175d5d, 0x174aae, 0x175ae5, 0x1043b8, 0x1fd2e5}, + {0x1fdd7f, 0x104641, 0x17565d, 0x17415d, 0x17415d, 0x105841, 0x1fd57f, + 0x000a00, 0x146f25, 0x10bc08, 0x09dc44, 0x130118, 0x0e444b, 0x001ee8, + 0x1fdbbb, 0x104ee1, 0x1747f7, 0x174004, 0x17504f, 0x104912, 0x1fd84f}, + {0x1fcb7f, 0x104f41, 0x17505d, 0x17585d, 0x17575d, 0x105141, 0x1fd57f, + 0x001300, 0x17c97c, 0x02b52c, 0x046a9f, 0x01083c, 0x03f290, 0x0017cc, + 0x1fcd60, 0x1057c5, 0x17512c, 0x175920, 0x175694, 0x104036, 0x1fde94}, + {0x1fdb7f, 0x105441, 0x174d5d, 0x17585d, 0x174c5d, 0x104c41, 0x1fd57f, + 0x001800, 0x16e44b, 0x02b52c, 0x12f1f2, 0x1a258a, 0x03f290, 0x001ca1, + 0x1fd0d6, 0x1057c5, 0x174a41, 0x175496, 0x175694, 0x104b5b, 0x1fd322}, + {0x1fd37f, 0x104741, 0x17475d, 0x175f5d, 0x175f5d, 0x105941, 0x1fd57f, + 0x001400, 0x1171f9, 0x0c8dcf, 0x15ed83, 0x108f20, 0x0dca73, 0x001f2f, + 0x1fda7c, 0x1040d9, 0x1759cf, 0x1741c3, 0x174188, 0x10472a, 0x1fd677}, + {0x1fcd7f, 0x105741, 0x17505d, 0x17545d, 0x17475d, 0x104941, 0x1fd57f, + 0x001b00, 0x1059ce, 0x05a95d, 0x046a9f, 0x03001c, 0x0e444b, 0x001fec, + 0x1fcd60, 0x104bb4, 0x17412c, 0x174100, 0x17404f, 0x104816, 0x1fde94}, + {0x1fdd7f, 0x105741, 0x17545d, 0x17445d, 0x17555d, 0x104f41, 0x1fd57f, + 0x000b00, 0x13fd97, 0x05a95d, 0x00f8d6, 0x028604, 0x0e444b, 0x001f2f, + 0x1fd9f2, 0x105bb4, 0x175365, 0x175718, 0x17404f, 0x1048d5, 0x1fda06}, + {0x1fc77f, 0x104841, 0x174e5d, 0x174b5d, 0x174f5d, 0x105041, 0x1fd57f, + 0x000400, 0x12d7a0, 0x1a16a2, 0x0a527c, 0x1d39fb, 0x04eee1, 0x0010d0, + 0x1fc358, 0x10544b, 0x1749cf, 0x1758e7, 0x174ae5, 0x10472a, 0x1fd0ac} +}; + +static void test_encode(void) +{ + QRinput *stream; + char num[9] = "01234567"; + unsigned char *frame; + int err = 0; + int x, y, w; + int mask; + QRcode *qrcode; + + testStart("Test encode (1-M)"); + stream = QRinput_new(); + if(stream == NULL) goto ABORT; + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + for(mask=0; mask<8; mask++) { + QRinput_setVersion(stream, 1); + QRinput_setErrorCorrectionLevel(stream, QR_ECLEVEL_M); + qrcode = QRcode_encodeMask(stream, mask); + if(qrcode == NULL) goto ABORT; + w = qrcode->width; + frame = qrcode->data; + for(y=0; y<w; y++) { + for(x=0; x<w; x++) { + if(((m1pat[mask][y] >> (20-x)) & 1) != (frame[y*w+x]&1)) { + printf("Diff in mask=%d (%d,%d)\n", mask, x, y); + err++; + } + } + } + QRcode_free(qrcode); + } + QRinput_free(stream); +ABORT: + testEnd(err); +} + +static void test_encode2(void) +{ + QRcode *qrcode; + + testStart("Test encode (2-H) (no padding test)"); + qrcode = QRcode_encodeString("abcdefghijk123456789012", 0, QR_ECLEVEL_H, QR_MODE_8, 0); + testEndExp(qrcode->version == 2); + QRcode_free(qrcode); +} + +static void test_encode3(void) +{ + QRcode *code1, *code2; + QRinput *input; + + testStart("Compare encodeString and encodeInput"); + code1 = QRcode_encodeString("0123456", 0, QR_ECLEVEL_L, QR_MODE_8, 0); + input = QRinput_new2(0, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_NUM, 7, (unsigned char *)"0123456"); + code2 = QRcode_encodeInput(input); + testEnd(memcmp(code1->data, code2->data, code1->width * code1->width)); + + QRcode_free(code1); + QRcode_free(code2); + QRinput_free(input); +} + +static void test_encodeNull(void) +{ + QRcode *qrcode; + + testStart("Test encode NULL."); + qrcode = QRcode_encodeString(NULL, 0, QR_ECLEVEL_H, QR_MODE_8, 0); + assert_null(qrcode, "QRcode_encodeString() returned something.\n"); + testFinish(); + if(qrcode != NULL) QRcode_free(qrcode); +} + + +static void test_encodeEmpty(void) +{ + QRcode *qrcode; + + testStart("Test encode an empty string."); + qrcode = QRcode_encodeString("", 0, QR_ECLEVEL_H, QR_MODE_8, 0); + assert_null(qrcode, "QRcode_encodeString() returned something.\n"); + testFinish(); + if(qrcode != NULL) QRcode_free(qrcode); +} + +static void test_encodeNull8(void) +{ + QRcode *qrcode; + + testStart("Test encode NULL."); + qrcode = QRcode_encodeString8bit(NULL, 0, QR_ECLEVEL_H); + assert_null(qrcode, "QRcode_encodeString8bit() returned something.\n"); + testFinish(); + if(qrcode != NULL) QRcode_free(qrcode); +} + + +static void test_encodeEmpty8(void) +{ + QRcode *qrcode; + + testStart("Test encode an empty string."); + qrcode = QRcode_encodeString8bit("", 0, QR_ECLEVEL_H); + assert_null(qrcode, "QRcode_encodeString8bit() returned something.\n"); + testFinish(); + if(qrcode != NULL) QRcode_free(qrcode); +} + +static void test_encodeLongData(void) +{ + QRinput *stream; + unsigned char data[7090]; + int maxlength[4][4] = {{7089,5596,3993,3057}, + {4296,3391,2420,1852}, + {2953,2331,1663,1273}, + {1817*2,1435*2,1024*2, 784*2}}; + int i, l, len, ret; + QRcode *qrcode; + + testStart("Encoding long data."); + + for(i=QR_MODE_NUM; i<=QR_MODE_KANJI; i++) { + if(i != QR_MODE_KANJI) { + memset(data, '0', maxlength[i][0] + 1); + } else { + for(l=0; l<=maxlength[i][0]/2+1; l++) { + data[l*2] = 0x93; data[l*2+1] = 0x5f; + } + } + for(l=QR_ECLEVEL_L; l<=QR_ECLEVEL_H; l++) { + stream = QRinput_new2(0, l); + ret = QRinput_append(stream, i, maxlength[i][l], data); + assert_zero(ret, "Failed to add %d-byte %s to a QRinput\n", maxlength[i][l], modeStr[i]); + qrcode = QRcode_encodeInput(stream); + assert_nonnull(qrcode, "(QRcode_encodeInput) failed to encode %d-byte %s in level %d.\n", maxlength[i][l], modeStr[i], l); + if(qrcode != NULL) { + QRcode_free(qrcode); + } + QRinput_free(stream); + + stream = QRinput_new2(0, l); + len = maxlength[i][l]; + if(i == QR_MODE_KANJI) { + len += 2; + } else { + len += 1; + } + ret = QRinput_append(stream, i, len, data); + if(ret == 0) { + qrcode = QRcode_encodeInput(stream); + assert_null(qrcode, "(QRcode_encodeInput) incorrectly succeeded to encode %d-byte %s in level %d.\n", len, modeStr[i], l); + if(qrcode != NULL) { + printf("version: %d\n", qrcode->version); + QRcode_free(qrcode); + } + } + QRinput_free(stream); + } + } + + testFinish(); +} + +static void test_encodeVer26Num(void) +{ + char data[3284]; + QRcode *qrcode; + + testStart("Encoding 3283 digits number. (issue #160)"); + + memset(data, '0', 3283); + data[3283] = '\0'; + qrcode = QRcode_encodeString(data, 0, QR_ECLEVEL_L, QR_MODE_8, 0); + assert_nonnull(qrcode, "(QRcode_encodeString) failed to encode 3283 digits number in level L.\n"); + assert_equal(qrcode->version, 26, "version number is %d (26 expected)\n", qrcode->version); + if(qrcode != NULL) { + QRcode_free(qrcode); + } + + QRinput *input; + QRinput_List *list; + + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(data, input, QR_MODE_8, 0); + list = input->head; + assert_equal(list->size, 3283, "chunk size is wrong. (%d, 3283 expected)\n", list->size); + QRinput_free(input); + + testFinish(); +} + +static void test_01234567(void) +{ + QRinput *stream; + char num[9] = "01234567"; + int i, err = 0; + QRcode *qrcode; + unsigned char correct[] = { +0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0x84, 0x03, 0x02, 0x03, 0x03, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, +0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc0, 0x84, 0x03, 0x03, 0x03, 0x03, 0xc0, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, +0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc0, 0x85, 0x02, 0x02, 0x02, 0x02, 0xc0, 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, +0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc0, 0x85, 0x03, 0x02, 0x02, 0x02, 0xc0, 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, +0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc0, 0x85, 0x02, 0x03, 0x01, 0x01, 0xc0, 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, +0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc0, 0x85, 0x02, 0x02, 0x00, 0x01, 0xc0, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, +0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0x91, 0x90, 0x91, 0x90, 0x91, 0xc0, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, +0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x85, 0x02, 0x02, 0x01, 0x01, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +0x85, 0x84, 0x85, 0x85, 0x85, 0x85, 0x91, 0x84, 0x84, 0x03, 0x02, 0x00, 0x01, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, +0x02, 0x02, 0x02, 0x03, 0x02, 0x03, 0x90, 0x03, 0x03, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, +0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x91, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, +0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x90, 0x02, 0x02, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, +0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x91, 0x03, 0x03, 0x02, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x81, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, +0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0x84, 0x03, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc0, 0x85, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, +0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc0, 0x85, 0x02, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, +0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc0, 0x85, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, 0xc0, 0x85, 0x02, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, +0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc0, 0x84, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, +0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0x85, 0x03, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00}; + + testStart("Encode 01234567 in 1-M"); + stream = QRinput_new2(1, QR_ECLEVEL_M); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + qrcode = QRcode_encodeInput(stream); + for(i=0; i<qrcode->width * qrcode->width; i++) { + if(qrcode->data[i] != correct[i]) { + err++; + } + } + testEnd(err); + QRinput_free(stream); + QRcode_free(qrcode); +} + +static void print_01234567(void) +{ + QRinput *stream; + char num[9] = "01234567"; + QRcode *qrcode; + + puts("\nPrinting QR code of '01234567'."); + stream = QRinput_new2(1, QR_ECLEVEL_M); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)num); + qrcode = QRcode_encodeInput(stream); + printQRcode(qrcode); + QRinput_free(stream); + QRcode_free(qrcode); +} + +static void test_invalid_input(void) +{ + QRinput *input; + QRcode *code; + + testStart("Testing invalid input."); + input = QRinput_new(); + QRinput_append(input, QR_MODE_AN, 5, (unsigned char *)"TEST1"); + input->version = -1; + input->level = QR_ECLEVEL_L; + code = QRcode_encodeInput(input); + assert_null(code, "invalid version(-1) was not checked.\n"); + if(code != NULL) QRcode_free(code); + + input->version = 41; + input->level = QR_ECLEVEL_L; + code = QRcode_encodeInput(input); + assert_null(code, "invalid version(41) access was not checked.\n"); + if(code != NULL) QRcode_free(code); + + input->version = 1; + input->level = (QRecLevel)(QR_ECLEVEL_H + 1); + code = QRcode_encodeInput(input); + assert_null(code, "invalid level(H+1) access was not checked.\n"); + if(code != NULL) QRcode_free(code); + + input->version = 1; + input->level = (QRecLevel)-1; + code = QRcode_encodeInput(input); + assert_null(code, "invalid level(-1) access was not checked.\n"); + if(code != NULL) QRcode_free(code); + + QRinput_free(input); + + testFinish(); +} + +static void test_struct_semilong(void) +{ + QRcode_List *codes, *list; + const char *str = "asdfasdfasdfasdfasdfASDFASDASDFASDFAsdfasdfasdfasdASDFASDFADSADadsfasdf"; + int num, size; + + testStart("Testing semi-long structured-append symbols"); + codes = QRcode_encodeString8bitStructured(str, 1, QR_ECLEVEL_L); + list = codes; + num = 0; + while(list != NULL) { + num++; + assert_equal(list->code->version, 1, "version number is %d (1 expected)\n", list->code->version); + list = list->next; + } + size = QRcode_List_size(codes); + assert_equal(num, size, "QRcode_List_size returns wrong size?"); + QRcode_List_free(codes); + + codes = QRcode_encodeStringStructured(str, 1, QR_ECLEVEL_L, QR_MODE_8, 1); + list = codes; + num = 0; + while(list != NULL) { + num++; + assert_equal(list->code->version, 1, "version number is %d (1 expected)\n", list->code->version); + list = list->next; + } + size = QRcode_List_size(codes); + assert_equal(num, size, "QRcode_List_size returns wrong size?"); + QRcode_List_free(codes); + + testFinish(); +} + +static void test_struct_example(void) +{ + QRcode_List *codes, *list; + const char *str = "an example of four Structured Append symbols,"; + int num; + + testStart("Testing the example of structured-append symbols"); + codes = QRcode_encodeString8bitStructured(str, 1, QR_ECLEVEL_M); + list = codes; + num = 0; + while(list != NULL) { + num++; + assert_equal(list->code->version, 1, "version number is %d (1 expected)\n", list->code->version); + list = list->next; + } + assert_equal(num, 4, "number of symbols is %d (4 expected).", num); + testFinish(); + QRcode_List_free(codes); +} + +static void test_null_free(void) +{ + testStart("Testing free NULL pointers"); + assert_nothing(QRcode_free(NULL), "Check QRcode_free(NULL).\n"); + assert_nothing(QRcode_List_free(NULL), "Check QRcode_List_free(NULL).\n"); + assert_nothing(QRraw_free(NULL), "Check QRraw_free(NULL).\n"); + testFinish(); +} + +static void test_encodeTooLongMQR(void) +{ + QRcode *code; + char *data[] = {"012345", "ABC0EFG", "0123456789", "0123456789ABCDEFG"}; + + testStart("Encode too large data for MQR."); + + code = QRcode_encodeStringMQR(data[0], 1, QR_ECLEVEL_L, QR_MODE_8, 0); + assert_nonnull(code, "6 byte length numeric string should be accepted to version 2 or larger.\n"); + assert_equal(code->version, 2, "6 byte length numeric string should be accepted to version 2.\n"); + if(code != NULL) { + QRcode_free(code); + } + + code = QRcode_encodeStringMQR(data[1], 2, QR_ECLEVEL_L, QR_MODE_8, 0); + assert_nonnull(code, "7 byte length alphanumeric string should be accepted to version 3 or larger.\n"); + assert_equal(code->version, 3, "7 byte length alphanumeric string should be accepted to version 3.\n"); + if(code != NULL) { + QRcode_free(code); + } + + code = QRcode_encodeString8bitMQR(data[2], 3, QR_ECLEVEL_L); + assert_nonnull(code, "9 byte length 8bit string should be accepted to version 4.\n"); + assert_equal(code->version, 4, "9 byte length 8bit string should be accepted to version 4.\n"); + if(code != NULL) { + QRcode_free(code); + } + + code = QRcode_encodeString8bitMQR(data[3], 4, QR_ECLEVEL_L); + assert_null(code, "16 byte length 8bit string was accepted to version 4.\n"); + assert_equal(errno, ERANGE, "errno != ERANGE\n"); + testFinish(); + + if(code != NULL) { + printQRcode(code); + QRcode_free(code); + } +} + +static void test_mqrraw_new(void) +{ + QRinput *stream; + char *num = "01234"; + unsigned char datacode[] = {0xa0, 0x62, 0x20}; + MQRRawCode *raw; + + testStart("Test MQRRaw_new()"); + stream = QRinput_newMQR(1, QR_ECLEVEL_L); + QRinput_append(stream, QR_MODE_NUM, 5, (unsigned char *)num); + + raw = MQRraw_new(stream); + assert_nonnull(raw, "Failed MQRraw_new().\n"); + assert_zero(raw->count, "MQRraw.count = %d != 0\n", raw->count); + assert_equal(raw->version, 1, "MQRraw.version was not as expected. (%d)\n", raw->version); + assert_equal(raw->dataLength, 3, "MQRraw.dataLength was not as expected.\n"); + assert_equal(raw->eccLength, 2, "MQRraw.eccLength was not as expected.\n"); + assert_zero(memcmp(raw->datacode, datacode, 3), "Datacode doesn't match.\n"); + + + QRinput_free(stream); + MQRraw_free(raw); + testFinish(); +} + +static void test_encodeData(void) +{ + QRcode *qrcode; + + testStart("Test QRencode_encodeData."); + qrcode = QRcode_encodeData(0, NULL, 0, QR_ECLEVEL_H); + assert_null(qrcode, "QRcode_encodeData(NULL, 0) returned something.\n"); + if(qrcode != NULL) QRcode_free(qrcode); + + qrcode = QRcode_encodeData(10, (unsigned char*)"test\0\0test", 0, QR_ECLEVEL_H); + assert_nonnull(qrcode, "QRcode_encodeData() failed.\n"); + if(qrcode != NULL) QRcode_free(qrcode); + + testFinish(); +} + +static void test_formatInfo(void) +{ + QRcode *qrcode; + QRecLevel level; + int mask; + int ret; + + testStart("Test format info in QR code."); + qrcode = QRcode_encodeString("AC-42", 1, QR_ECLEVEL_H, QR_MODE_8, 1); + ret = QRcode_decodeFormat(qrcode, &level, &mask); + assert_zero(ret, "Failed to decode.\n"); + assert_equal(level, QR_ECLEVEL_H, "Decoded format is wrong.\n"); + + if(qrcode != NULL) QRcode_free(qrcode); + + testFinish(); +} + +static void test_formatInfoMQR(void) +{ + QRcode *qrcode; + QRecLevel level; + int version, mask; + int i, ret; + + testStart("Test format info in Micro QR code."); + for(i=0; i<8; i++) { + qrcode = QRcode_encodeStringMQR("1", + MQRformat[i].version, + MQRformat[i].level, + QR_MODE_8, 1); + ret = QRcode_decodeFormatMQR(qrcode, &version, &level, &mask); + assert_zero(ret, "Failed to decode.\n"); + assert_equal(MQRformat[i].version, version, "Decoded verion is wrong.\n"); + assert_equal(MQRformat[i].level, level, "Decoded level is wrong.\n"); + QRcode_free(qrcode); + } + + testFinish(); +} + +static void test_decodeSimple(void) +{ + char *str = "AC-42"; + QRcode *qrcode; + QRdata *qrdata; + + testStart("Test code words."); + qrcode = QRcode_encodeString(str, 1, QR_ECLEVEL_H, QR_MODE_8, 1); + qrdata = QRcode_decode(qrcode); + + assert_nonnull(qrdata, "Failed to decode.\n"); + if(qrdata != NULL) { + assert_equal(strlen(str), qrdata->size, "Lengths of input/output mismatched: %d, expected %d.\n", qrdata->size, (int)strlen(str)); + assert_zero(strncmp(str, (char *)(qrdata->data), qrdata->size), "Decoded data %s is different from the original %s\n", qrdata->data, str); + } + if(qrdata != NULL) QRdata_free(qrdata); + if(qrcode != NULL) QRcode_free(qrcode); + + testFinish(); +} + + +static void test_decodeLong(void) +{ + char *str = "12345678901234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ?????????????"; + QRcode *qrcode; + QRdata *qrdata; + + testStart("Test code words (long, splitted)."); + qrcode = QRcode_encodeString(str, 0, QR_ECLEVEL_H, QR_MODE_8, 1); + qrdata = QRcode_decode(qrcode); + + assert_nonnull(qrdata, "Failed to decode.\n"); + if(qrdata != NULL) { + assert_equal(strlen(str), qrdata->size, "Lengths of input/output mismatched.\n"); + assert_zero(strncmp(str, (char *)(qrdata->data), qrdata->size), "Decoded data %s is different from the original %s\n", qrdata->data, str); + } + if(qrdata != NULL) QRdata_free(qrdata); + if(qrcode != NULL) QRcode_free(qrcode); + + testFinish(); +} + +static void test_decodeVeryLong(void) +{ + char str[4000]; + int i; + QRcode *qrcode; + QRdata *qrdata; + + testStart("Test code words (very long string)."); + + for(i=0; i<3999; i++) { + str[i] = decodeAnTable[(int)drand(45)]; + } + str[3999] = '\0'; + + qrcode = QRcode_encodeString(str, 0, QR_ECLEVEL_L, QR_MODE_8, 0); + qrdata = QRcode_decode(qrcode); + + assert_nonnull(qrdata, "Failed to decode.\n"); + if(qrdata != NULL) { + assert_equal(strlen(str), qrdata->size, "Lengths of input/output mismatched.\n"); + assert_zero(strncmp(str, (char *)(qrdata->data), qrdata->size), "Decoded data %s is different from the original %s\n", qrdata->data, str); + } + if(qrdata != NULL) QRdata_free(qrdata); + if(qrcode != NULL) QRcode_free(qrcode); + + testFinish(); +} + +static void test_decodeShortMQR(void) +{ + char str[]="55"; + QRcode *qrcode; + QRdata *qrdata; + int i; + + testStart("Test code words (MQR)."); + for(i=0; i<8; i++) { + qrcode = QRcode_encodeStringMQR(str, + MQRformat[i].version, + MQRformat[i].level, + QR_MODE_8, 1); + qrdata = QRcode_decodeMQR(qrcode); + + assert_nonnull(qrdata, "Failed to decode.\n"); + assert_zero(strcmp((char *)qrdata->data, str), "Decoded data (%s) mismatched (%s)\n", (char *)qrdata->data, str); + if(qrdata != NULL) QRdata_free(qrdata); + if(qrcode != NULL) QRcode_free(qrcode); + } + + testFinish(); +} + +static void test_oddBitCalcMQR(void) +{ + /* test issue #25 (odd bits calculation bug) */ + /* test pattern contributed by vlad417 */ + TestString tests[] = { + {"46194", 1, QR_ECLEVEL_L, QR_MODE_8, 1}, + {"WBA5Y47YPQQ", 3, QR_ECLEVEL_L, QR_MODE_8, 1} + }; + QRcode *qrcode; + QRdata *qrdata; + int i; + + testStart("Odd bits calculation bug checking (MQR)."); + + for(i=0; i<_countof(tests); i++) { + qrcode = QRcode_encodeStringMQR(tests[i].str, + tests[i].version, + tests[i].level, + tests[i].hint, + tests[i].casesensitive); + assert_nonnull(qrcode, "Failed to encode: %s\n", tests[i].str); + if(qrcode == NULL) continue; + qrdata = QRcode_decodeMQR(qrcode); + assert_nonnull(qrdata, "Failed to decode.\n"); + assert_zero(strcmp((char *)qrdata->data, tests[i].str), "Decoded data (%s) mismatched (%s)\n", (char *)qrdata->data, tests[i].str); + if(qrdata != NULL) QRdata_free(qrdata); + QRcode_free(qrcode); + } + + testFinish(); +} + +static void test_invalid_inputMQR(void) +{ + QRinput *input; + QRcode *code; + + testStart("Testing invalid input (MQR)."); + input = QRinput_newMQR(1, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_AN, 5, (unsigned char *)"TEST1"); + input->version = -1; + input->level = QR_ECLEVEL_L; + code = QRcode_encodeInput(input); + assert_null(code, "invalid version(-1) was not checked.\n"); + if(code != NULL) QRcode_free(code); + + input->version = 5; + input->level = QR_ECLEVEL_L; + code = QRcode_encodeInput(input); + assert_null(code, "invalid version(5) access was not checked.\n"); + if(code != NULL) QRcode_free(code); + + input->version = 1; + input->level = (QRecLevel)(QR_ECLEVEL_H); + code = QRcode_encodeInput(input); + assert_null(code, "invalid level(H) access was not checked.\n"); + if(code != NULL) QRcode_free(code); + + input->version = 1; + input->level = (QRecLevel)-1; + code = QRcode_encodeInput(input); + assert_null(code, "invalid level(-1) access was not checked.\n"); + if(code != NULL) QRcode_free(code); + + QRinput_free(input); + + testFinish(); +} + +static void test_mqrencode(void) +{ + char *str = "MICROQR"; + char pattern[] = { + "#######_#_#_#_#" + "#_____#_#__####" + "#_###_#_#_####_" + "#_###_#_#__##_#" + "#_###_#___#__##" + "#_____#____#_#_" + "#######__##_#_#" + "_________#__#__" + "#___#__####_#_#" + "_#######_#_##_#" + "##___#_#____#__" + "_##_#_####____#" + "#__###___#__##_" + "_###_#_###_#_#_" + "##____####_###_" + }; + QRcode qrcode; + QRdata *qrdata; + unsigned char *frame; + int i; + + testStart("Encoding test (MQR)."); + + qrcode.width = 15; + qrcode.version = 3; + + frame = MQRspec_newFrame(qrcode.version); + for(i=0; i<225; i++) { + frame[i] ^= (pattern[i] == '#')?1:0; + } + + qrcode.data = frame; + qrdata = QRcode_decodeMQR(&qrcode); + assert_equal(qrdata->version, 3, "Format info decoder returns wrong version number: %d (%d expected)\n", qrdata->version, 3); + assert_equal(qrdata->level, 1, "Format info decoder returns wrong level: %d (%d expected)\n", qrdata->level, 1); + assert_zero(strcmp((char *)qrdata->data, str), "Decoded data (%s) mismatched (%s)\n", (char *)qrdata->data, str); + + QRdata_free(qrdata); + free(frame); + + testFinish(); +} + +static void test_apiversion(void) +{ + int major_version, minor_version, micro_version; + char *str, *str2; + + testStart("API Version check"); + QRcode_APIVersion(&major_version, &minor_version, µ_version); + assert_equal(major_version, MAJOR_VERSION, "Major version number mismatched: %d (%d expected)\n", major_version, MAJOR_VERSION); + assert_equal(minor_version, MINOR_VERSION, "Minor version number mismatched: %d (%d expected)\n", minor_version, MINOR_VERSION); + assert_equal(micro_version, MICRO_VERSION, "Micro version number mismatched: %d (%d expected)\n", micro_version, MICRO_VERSION); + str = QRcode_APIVersionString(); + str2 = QRcode_APIVersionString(); + assert_zero(strcmp(VERSION, str), "Version string mismatched: %s (%s expected)\n", str, VERSION); + assert_equal(str, str2, "Version strings are not identical."); + testFinish(); +} + +int main(int argc, char **argv) +{ + int tests = 33; + testInit(tests); + test_iterate(); + test_iterate2(); + test_filler(); + test_format(); + test_encode(); + test_encode2(); + test_encode3(); + test_encodeNull(); + test_encodeEmpty(); + test_encodeNull8(); + test_encodeEmpty8(); + test_encodeLongData(); + test_encodeVer26Num(); + test_01234567(); + test_invalid_input(); + test_struct_example(); + test_struct_semilong(); + test_null_free(); + test_qrraw_new(); + test_mqrraw_new(); + test_encodeData(); + test_formatInfo(); + test_decodeSimple(); + test_decodeLong(); + test_decodeVeryLong(); + test_fillerMQR(); + test_formatInfoMQR(); + test_encodeTooLongMQR(); + test_decodeShortMQR(); + test_oddBitCalcMQR(); + test_invalid_inputMQR(); + test_mqrencode(); + test_apiversion(); + testReport(tests); + + if(argc > 1) { + print_filler(); + print_01234567(); + print_fillerMQR(); + } + + return 0; +} diff --git a/genqrcode/tests/test_qrinput.c b/genqrcode/tests/test_qrinput.c new file mode 100644 index 0000000000..2aab36a8b6 --- /dev/null +++ b/genqrcode/tests/test_qrinput.c @@ -0,0 +1,1130 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "common.h" +#include "../qrinput.h" +#include "../qrencode_inner.h" +#include "../split.h" +#include "decoder.h" + +/* taken from the Table 7 of JIS X0510:2018 (pp. 31-34) */ +static int maxCharacterLengths[40][4] = { + { 41, 25, 17, 10}, /* ver 1 */ + { 77, 47, 32, 20}, /* ver 2 */ + { 127, 77, 53, 32}, /* ver 3 */ + { 187, 114, 78, 48}, /* ver 4 */ + { 255, 154, 106, 65}, /* ver 5 */ + { 322, 195, 134, 82}, /* ver 6 */ + { 370, 224, 154, 95}, /* ver 7 */ + { 461, 279, 192, 118}, /* ver 8 */ + { 552, 335, 230, 141}, /* ver 9 */ + { 652, 395, 271, 167}, /* ver 10 */ + { 772, 468, 321, 198}, /* ver 11 */ + { 883, 535, 367, 226}, /* ver 12 */ + {1022, 619, 425, 262}, /* ver 13 */ + {1101, 667, 458, 282}, /* ver 14 */ + {1250, 758, 520, 320}, /* ver 15 */ + {1408, 854, 586, 361}, /* ver 16 */ + {1548, 938, 644, 397}, /* ver 17 */ + {1725, 1046, 718, 442}, /* ver 18 */ + {1903, 1153, 792, 488}, /* ver 19 */ + {2061, 1249, 858, 528}, /* ver 20 */ + {2232, 1352, 929, 572}, /* ver 21 */ + {2409, 1460, 1003, 618}, /* ver 22 */ + {2620, 1588, 1091, 672}, /* ver 23 */ + {2812, 1704, 1171, 721}, /* ver 24 */ + {3057, 1853, 1273, 784}, /* ver 25 */ + {3283, 1990, 1367, 842}, /* ver 26 */ + {3517, 2132, 1465, 902}, /* ver 27 */ + {3669, 2223, 1528, 940}, /* ver 28 */ + {3909, 2369, 1628, 1002}, /* ver 29 */ + {4158, 2520, 1732, 1066}, /* ver 30 */ + {4417, 2677, 1840, 1132}, /* ver 31 */ + {4686, 2840, 1952, 1201}, /* ver 32 */ + {4965, 3009, 2068, 1273}, /* ver 33 */ + {5253, 3183, 2188, 1347}, /* ver 34 */ + {5529, 3351, 2303, 1417}, /* ver 35 */ + {5836, 3537, 2431, 1496}, /* ver 36 */ + {6153, 3729, 2563, 1577}, /* ver 37 */ + {6479, 3927, 2699, 1661}, /* ver 38 */ + {6743, 4087, 2809, 1729}, /* ver 39 */ + {7089, 4296, 2953, 1817} /* ver 40 */ +}; + +static int encodeAndCheckBStream(int mqr, int version, QRecLevel level, QRencodeMode mode, char *data, char *correct) +{ + QRinput *input; + BitStream *bstream; + int ret; + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + QRinput_append(input, mode, strlen(data), (unsigned char *)data); + bstream = BitStream_new(); + QRinput_getBitStream(input, bstream); + ret = cmpBin(correct, bstream); + if(ret) { + printf("result : "); + printBstream(bstream); + printf("correct: %s\n", correct); + } + QRinput_free(input); + BitStream_free(bstream); + + return ret; +} + +static int mergeAndCheckBStream(int mqr, QRencodeMode mode, char *data, char *correct) +{ + QRinput *input; + BitStream *bstream; + int ret; + + if(mqr) { + input = QRinput_newMQR(1, QR_ECLEVEL_L); + } else { + input = QRinput_new(); + } + QRinput_append(input, mode, strlen(data), (unsigned char *)data); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + ret = cmpBin(correct, bstream); + + QRinput_free(input); + BitStream_free(bstream); + + return ret; +} + +static void test_encodeKanji(void) +{ + char str[5]= {0x93, 0x5f, 0xe4, 0xaa, 0x00}; + char *correct = "10000000001001101100111111101010101010"; + + testStart("Encoding kanji stream."); + testEnd(mergeAndCheckBStream(0, QR_MODE_KANJI, str, correct)); +} + +static void test_encode8(void) +{ + char str[] = "AC-42"; + char correct[] = "0100000001010100000101000011001011010011010000110010"; + + testStart("Encoding 8bit stream."); + testEnd(mergeAndCheckBStream(0, QR_MODE_8, str, correct)); +} + +static void test_encode8_versionup(void) +{ + QRinput *stream; + BitStream *bstream; + char *str; + int version; + + testStart("Encoding 8bit stream. (auto-version up test)"); + str = (char *)malloc(2900); + memset(str, 0xff, 2900); + stream = QRinput_new(); + bstream = BitStream_new(); + QRinput_append(stream, QR_MODE_8, 2900, (unsigned char *)str); + QRinput_mergeBitStream(stream, bstream); + version = QRinput_getVersion(stream); + assert_equal(version, 40, "Version is %d (40 expected).\n", version); + testFinish(); + QRinput_free(stream); + BitStream_free(bstream); + free(str); +} + +static void test_encodeAn(void) +{ + char *str = "AC-42"; + char correct[] = "00100000001010011100111011100111001000010"; + + testStart("Encoding alphabet-numeric stream."); + testEnd(mergeAndCheckBStream(0, QR_MODE_AN, str, correct)); +} + +static void test_encodeAn2(void) +{ + QRinput *stream; + char str[] = "!,;$%"; + int ret; + + testStart("Encoding INVALID alphabet-numeric stream."); + stream = QRinput_new(); + ret = QRinput_append(stream, QR_MODE_AN, 5, (unsigned char *)str); + testEnd(!ret); + QRinput_free(stream); +} + +static void test_encodeNumeric(void) +{ + char *str = "01234567"; + char correct[] = "00010000001000000000110001010110011000011"; + + testStart("Encoding numeric stream. (8 digits)"); + testEnd(mergeAndCheckBStream(0, QR_MODE_NUM, str, correct)); +} + +static void test_encodeNumeric_versionup(void) +{ + QRinput *stream; + BitStream *bstream; + char *str; + int version; + + testStart("Encoding numeric stream. (auto-version up test)"); + str = (char *)malloc(1050); + memset(str, '1', 1050); + stream = QRinput_new2(0, QR_ECLEVEL_L); + bstream = BitStream_new(); + QRinput_append(stream, QR_MODE_NUM, 1050, (unsigned char *)str); + QRinput_mergeBitStream(stream, bstream); + version = QRinput_getVersion(stream); + assert_equal(version, 14, "Version is %d (14 expected).", version); + testFinish(); + QRinput_free(stream); + BitStream_free(bstream); + free(str); +} + +static void test_encodeNumericPadded(void) +{ + char *str = "01234567"; + char *correct; + char *correctHead = "000100000010000000001100010101100110000110000000"; + int i, ret; + + testStart("Encoding numeric stream. (8 digits)(padded)"); + correct = (char *)malloc(19 * 8 + 1); + correct[0] = '\0'; + strcat(correct, correctHead); + for(i=0; i<13; i++) { + strcat(correct, (i&1)?"00010001":"11101100"); + } + ret = encodeAndCheckBStream(0, 0, QR_ECLEVEL_L, QR_MODE_NUM, str, correct); + testEnd(ret); + + free(correct); +} + +static void test_encodeNumericPadded2(void) +{ + char *str = "0123456"; + char *correct; + char *correctHead = "000100000001110000001100010101100101100000000000"; + int i, ret; + + testStart("Encoding numeric stream. (7 digits)(padded)"); + correct = (char *)malloc(19 * 8 + 1); + correct[0] = '\0'; + strcat(correct, correctHead); + for(i=0; i<13; i++) { + strcat(correct, (i&1)?"00010001":"11101100"); + } + ret = encodeAndCheckBStream(0, 0, QR_ECLEVEL_L, QR_MODE_NUM, str, correct); + testEnd(ret); + + free(correct); +} + +static void test_padding(void) +{ + QRinput *input; + BitStream *bstream; + int i, size; + char data[] = "0123456789ABCDeFG"; + unsigned char c; + + testStart("Padding bit check. (less than 5 bits)"); + input = QRinput_new2(1, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_8, 17, (unsigned char *)data); + bstream = BitStream_new(); + QRinput_getBitStream(input, bstream); + size = BitStream_size(bstream); + assert_equal(size, 152, "# of bit is incorrect (%d != 152).\n", size); + c = 0; + for(i=0; i<4; i++) { + c += bstream->data[size - i - 1]; + } + assert_zero(c, "Padding bits are not zero."); + testFinish(); + + QRinput_free(input); + BitStream_free(bstream); +} + +static void test_padding2(void) +{ + QRinput *input; + BitStream *bstream; + int i, size, ret; + char data[] = "0123456789ABCDeF"; + char correct[153]; + unsigned char c; + + testStart("Padding bit check. (1 or 2 padding bytes)"); + + /* 16 byte data (4 bit terminator and 1 byte padding) */ + memset(correct, 0, 153); + memcpy(correct, "010000010000", 12); + for(size=0; size<16; size++) { + c = 0x80; + for(i=0; i<8; i++) { + correct[size * 8 + i + 12] = (data[size]&c)?'1':'0'; + c = c >> 1; + } + } + memcpy(correct + 140, "000011101100", 12); + + input = QRinput_new2(1, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_8, 16, (unsigned char *)data); + bstream = BitStream_new(); + QRinput_getBitStream(input, bstream); + size = BitStream_size(bstream); + assert_equal(size, 152, "16byte: # of bit is incorrect (%d != 152).\n", size); + ret = ncmpBin(correct, bstream, 152); + assert_zero(ret, "Padding bits incorrect.\n"); + + QRinput_free(input); + BitStream_free(bstream); + + /* 15 byte data (4 bit terminator and 2 byte paddings) */ + + memcpy(correct, "010000001111", 12); + memcpy(correct + 132, "00001110110000010001", 20); + + input = QRinput_new2(1, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_8, 15, (unsigned char *)data); + bstream = BitStream_new(); + QRinput_getBitStream(input, bstream); + size = BitStream_size(bstream); + assert_equal(size, 152, "15byte: # of bit is incorrect (%d != 152).\n", size); + ret = ncmpBin(correct, bstream, 152); + assert_zero(ret, "Padding bits incorrect.\n"); + + testFinish(); + + QRinput_free(input); + BitStream_free(bstream); +} + +static void test_encodeNumeric2(void) +{ + char *str = "0123456789012345"; + char *correct = "00010000010000000000110001010110011010100110111000010100111010100101"; + + testStart("Encoding numeric stream. (16 digits)"); + testEnd(mergeAndCheckBStream(0, QR_MODE_NUM, str, correct)); +} + +static void test_encodeNumeric3(void) +{ + char *str = "0123456"; + char *correct = "0001 0000000111 0000001100 0101011001 0110"; + + testStart("Encoding numeric stream. (7 digits)"); + testEnd(mergeAndCheckBStream(0, QR_MODE_NUM, str, correct)); +} + +static void test_encodeAnNum(void) +{ + QRinput *input; + BitStream *bstream; + + testStart("Bit length check of alpha-numeric stream. (11 + 12)"); + input = QRinput_new(); + QRinput_append(input, QR_MODE_AN, 11, (unsigned char *)"ABCDEFGHIJK"); + QRinput_append(input, QR_MODE_NUM, 12, (unsigned char *)"123456789012"); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + testEndExp(BitStream_size(bstream) == 128); + QRinput_free(input); + BitStream_free(bstream); + + testStart("Bit length check of alphabet stream. (23)"); + input = QRinput_new(); + QRinput_append(input, QR_MODE_AN, 23, (unsigned char *)"ABCDEFGHIJK123456789012"); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + testEndExp(BitStream_size(bstream) == 140); + QRinput_free(input); + BitStream_free(bstream); +} + +static void test_struct_listop(void) +{ + QRinput_Struct *s; + QRinput *inputs[5]; + QRinput_InputList *l; + int i, ret; + + testStart("QRinput_Struct list operation test."); + s = QRinput_Struct_new(); + QRinput_Struct_setParity(s, 10); + assert_nonnull(s, "QRinput_Struct_new() failed."); + assert_equal(s->parity, 10, "QRinput_Struct_setParity() failed."); + + for(i=0; i<5; i++) { + inputs[i] = QRinput_new(); + QRinput_append(inputs[i], QR_MODE_AN, 5, (unsigned char *)"ABCDE"); + ret = QRinput_Struct_appendInput(s, inputs[i]); + } + assert_equal(ret, 5, "QRinput_Struct_appendInput() returns wrong num?"); + assert_equal(s->size, 5, "QRiput_Struct.size counts wrong number."); + + l = s->head; + i = 0; + while(l != NULL) { + assert_equal(l->input, inputs[i], "QRinput_Struct input list order would be wrong?"); + l = l->next; + i++; + } + + QRinput_Struct_free(s); + testFinish(); +} + +static void test_insertStructuredAppendHeader(void) +{ + QRinput *stream; + char correct[] = "0011000011111010010101000000000101000001"; + BitStream *bstream; + int ret; + + testStart("Insert a structured-append header"); + stream = QRinput_new(); + bstream = BitStream_new(); + QRinput_append(stream, QR_MODE_8, 1, (unsigned char *)"A"); + ret = QRinput_insertStructuredAppendHeader(stream, 16, 1, 0xa5); + assert_zero(ret, "QRinput_insertStructuredAppendHeader() returns nonzero.\n"); + QRinput_mergeBitStream(stream, bstream); + assert_nonnull(bstream->data, "Bstream->data is null."); + assert_zero(cmpBin(correct, bstream), "bitstream is wrong."); + testFinish(); + + QRinput_free(stream); + BitStream_free(bstream); +} + +static void test_insertStructuredAppendHeader_error(void) +{ + QRinput *stream; + int ret; + + testStart("Insert a structured-append header (errors expected)"); + stream = QRinput_new(); + QRinput_append(stream, QR_MODE_8, 1, (unsigned char *)"A"); + ret = QRinput_insertStructuredAppendHeader(stream, 17, 1, 0xa5); + assert_equal(-1, ret, "QRinput_insertStructuredAppendHeader() returns 0."); + assert_equal(EINVAL, errno, "errno is not set correctly (%d returned).", errno); + ret = QRinput_insertStructuredAppendHeader(stream, 16, 17, 0xa5); + assert_equal(-1, ret, "QRinput_insertStructuredAppendHeader() returns 0."); + assert_equal(EINVAL, errno, "errno is not set correctly (%d returned).", errno); + ret = QRinput_insertStructuredAppendHeader(stream, 16, 0, 0xa5); + assert_equal(-1, ret, "QRinput_insertStructuredAppendHeader() returns 0."); + assert_equal(EINVAL, errno, "errno is not set correctly (%d returned).", errno); + testFinish(); + + QRinput_free(stream); +} + +static void test_struct_insertStructuredAppendHeaders(void) +{ + QRinput *input; + QRinput_Struct *s; + QRinput_InputList *p; + int i; + + testStart("Insert structured-append headers to a QRinput_Struct."); + s = QRinput_Struct_new(); + for(i=0; i<10; i++) { + input = QRinput_new(); + QRinput_append(input, QR_MODE_8, 1, (unsigned char *)"A"); + QRinput_Struct_appendInput(s, input); + } + QRinput_Struct_insertStructuredAppendHeaders(s); + p = s->head; + i = 1; + while(p != NULL) { + assert_equal(p->input->head->mode, QR_MODE_STRUCTURE, "a structured-append header is not inserted."); + assert_equal(p->input->head->data[0], 10, "size of the structured-header is wrong: #%d, %d should be %d\n", i, p->input->head->data[0], 10); + assert_equal(p->input->head->data[1], i, "index of the structured-header is wrong: #%d, %d should be %d\n", i, p->input->head->data[1], i); + assert_equal(p->input->head->data[2], 0, "parity of the structured-header is wrong: #%d\n", i); + p = p->next; + i++; + } + testFinish(); + QRinput_Struct_free(s); +} + +static int check_lengthOfCode(QRencodeMode mode, char *data, int size, int version) +{ + QRinput *input; + BitStream *b; + size_t bits; + int bytes; + + input = QRinput_new(); + QRinput_setVersion(input, version); + QRinput_append(input, mode, size, (unsigned char *)data); + b = BitStream_new(); + QRinput_mergeBitStream(input, b); + bits = BitStream_size(b); + bytes = QRinput_lengthOfCode(mode, version, bits); + QRinput_free(input); + BitStream_free(b); + + return bytes; +} + +static void test_lengthOfCode_num(void) +{ + int i, bytes; + char *data; + + data = (char *)malloc(8000); + for(i=0; i<8000; i++) { + data[i] = '0' + i % 10; + } + + testStart("Checking length of code (numeric)"); + for(i=1; i<=9; i++) { + bytes = check_lengthOfCode(QR_MODE_NUM, data, i, 1); + assert_equal(i, bytes, "lengthOfCode failed. (QR_MODE_NUM, version:1, size:%d)\n", i); + } + for(i=1023; i<=1025; i++) { + bytes = check_lengthOfCode(QR_MODE_NUM, data, i, 1); + assert_equal(1023, bytes, "lengthOfCode failed. (QR_MODE_NUM, version:1, size:%d)\n", i); + } + testFinish(); + free(data); +} + +static void test_lengthOfCode_kanji(void) +{ + int i, bytes; + unsigned char str[12]= {0x93, 0x5f, 0xe4, 0xaa, 0x81, 0x40, 0x9f, 0xfc, 0xe0, 0x40, 0xeb, 0xbf}; + + testStart("Checking length of code (kanji)"); + for(i=2; i<=12; i+=2) { + bytes = check_lengthOfCode(QR_MODE_KANJI, (char *)str, i, 1); + assert_equal(i, bytes, "lengthOfCode failed. (QR_MODE_KANJI, version:1, size:%d)\n", i); + } + testFinish(); +} + +static void test_struct_split_example(void) +{ + QRinput *input; + QRinput_Struct *s; + QRinput_InputList *e; + QRinput_List *l; + const char *str[4] = { "an example ", "of four Str", "uctured Appe", "nd symbols,"}; + int i; + BitStream *bstream; + + testStart("Testing the example of structured-append symbols"); + s = QRinput_Struct_new(); + for(i=0; i<4; i++) { + input = QRinput_new2(1, QR_ECLEVEL_M); + QRinput_append(input, QR_MODE_8, strlen(str[i]), (unsigned char *)str[i]); + QRinput_Struct_appendInput(s, input); + } + QRinput_Struct_insertStructuredAppendHeaders(s); + e = s->head; + i = 0; + while(e != NULL) { + bstream = BitStream_new(); + QRinput_mergeBitStream(e->input, bstream); + BitStream_free(bstream); + l = e->input->head->next; + assert_equal(l->mode, QR_MODE_8, "#%d: wrong mode (%d).\n", i, l->mode); + assert_equal(e->input->level, QR_ECLEVEL_M, "#%d: wrong level (%d).\n", i, e->input->level); + + e = e->next; + i++; + } + testFinish(); + QRinput_Struct_free(s); +} + +static void test_struct_split_tooLarge(void) +{ + QRinput *input; + QRinput_Struct *s; + char *str; + int errsv; + + testStart("Testing structured-append symbols. (too large data)"); + str = (char *)malloc(128); + memset(str, 'a', 128); + input = QRinput_new2(1, QR_ECLEVEL_H); + QRinput_append(input, QR_MODE_8, 128, (unsigned char *)str); + s = QRinput_splitQRinputToStruct(input); + errsv = errno; + assert_null(s, "returns non-null."); + assert_equal(errsv, ERANGE, "did not return ERANGE."); + testFinish(); + if(s != NULL) QRinput_Struct_free(s); + QRinput_free(input); + free(str); +} + +static void test_struct_split_invalidVersion(void) +{ + QRinput *input; + QRinput_Struct *s; + char *str; + int errsv; + + testStart("Testing structured-append symbols. (invalid version 0)"); + str = (char *)malloc(128); + memset(str, 'a', 128); + input = QRinput_new2(0, QR_ECLEVEL_H); + QRinput_append(input, QR_MODE_8, 128, (unsigned char *)str); + s = QRinput_splitQRinputToStruct(input); + errsv = errno; + assert_null(s, "returns non-null."); + assert_equal(errsv, ERANGE, "did not return ERANGE."); + testFinish(); + if(s != NULL) QRinput_Struct_free(s); + QRinput_free(input); + free(str); +} + +static void test_struct_singlestructure(void) +{ + QRinput *input; + QRinput_Struct *s; + char *str = "TEST"; + + testStart("Testing structured-append symbols. (single structure)"); + input = QRinput_new2(10, QR_ECLEVEL_H); + QRinput_append(input, QR_MODE_AN, strlen(str), (unsigned char *)str); + s = QRinput_splitQRinputToStruct(input); + assert_nonnull(s, "must return a code."); + assert_equal(s->size, 1, "size must be 1, but %d returned.", s->size); + if(s->size != 1) { + printQRinputStruct(s); + } + testFinish(); + if(s != NULL) QRinput_Struct_free(s); + QRinput_free(input); +} + +static void test_splitentry(void) +{ + QRinput *i1, *i2; + QRinput_List *e; + const char *str = "abcdefghij"; + int size1, size2, i; + unsigned char *d1, *d2; + + testStart("Testing QRinput_splitEntry. (next == NULL)"); + i1 = QRinput_new(); + QRinput_append(i1, QR_MODE_8, strlen(str), (unsigned char *)str); + + i2 = QRinput_dup(i1); + e = i2->head; + QRinput_splitEntry(e, 4); + + size1 = size2 = 0; + e = i1->head; + while(e != NULL) { + size1 += e->size; + e = e->next; + } + e = i2->head; + while(e != NULL) { + size2 += e->size; + e = e->next; + } + + d1 = (unsigned char *)malloc(size1); + e = i1->head; + i = 0; + while(e != NULL) { + memcpy(&d1[i], e->data, e->size); + i += e->size; + e = e->next; + } + d2 = (unsigned char *)malloc(size2); + e = i2->head; + i = 0; + while(e != NULL) { + memcpy(&d2[i], e->data, e->size); + i += e->size; + e = e->next; + } + + assert_equal(size1, size2, "sizes are different. (%d:%d)\n", size1, size2); + assert_equal(i2->head->size, 4, "split failed (first half)"); + assert_equal(i2->head->next->size, 6, "split failed(second half)"); + assert_zero(memcmp(d1, d2, size1), "strings are different."); + QRinput_free(i1); + QRinput_free(i2); + free(d1); + free(d2); + + testFinish(); +} + +static void test_splitentry2(void) +{ + QRinput *i1, *i2; + QRinput_List *e; + const char *str = "abcdefghij"; + int size1, size2, i; + unsigned char *d1, *d2; + + testStart("Testing QRinput_splitEntry. (next != NULL)"); + i1 = QRinput_new(); + QRinput_append(i1, QR_MODE_8, strlen(str), (unsigned char *)str); + QRinput_append(i1, QR_MODE_8, strlen(str), (unsigned char *)str); + + i2 = QRinput_dup(i1); + e = i2->head; + QRinput_splitEntry(e, 4); + + size1 = size2 = 0; + e = i1->head; + while(e != NULL) { + size1 += e->size; + e = e->next; + } + e = i2->head; + while(e != NULL) { + size2 += e->size; + e = e->next; + } + + d1 = (unsigned char *)malloc(size1); + e = i1->head; + i = 0; + while(e != NULL) { + memcpy(&d1[i], e->data, e->size); + i += e->size; + e = e->next; + } + d2 = (unsigned char *)malloc(size2); + e = i2->head; + i = 0; + while(e != NULL) { + memcpy(&d2[i], e->data, e->size); + i += e->size; + e = e->next; + } + + assert_equal(size1, size2, "sizes are different. (%d:%d)\n", size1, size2); + assert_equal(i2->head->size, 4, "split failed (first half)"); + assert_equal(i2->head->next->size, 6, "split failed(second half)"); + assert_zero(memcmp(d1, d2, size1), "strings are different."); + QRinput_free(i1); + QRinput_free(i2); + free(d1); + free(d2); + + testFinish(); +} + +static void test_splitentry3(void) +{ + QRinput *input; + QRinput_Struct *s; + QRinput_List *e00, *e01, *e10, *e11; + QRinput_InputList *list; + const char *str = "abcdefghijklmno"; + + testStart("Testing QRinput_splitEntry. (does not split an entry)"); + /* version 1 symbol contains 152 bit (19 byte) data. + * 20 bits for a structured-append header, so 132 bits can be used. + * 15 bytes of 8-bit data is suitable for the symbol. + * (mode(4) + length(8) + data(120) == 132.) + */ + input = QRinput_new2(1, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_8, strlen(str), (unsigned char *)str); + QRinput_append(input, QR_MODE_8, strlen(str), (unsigned char *)str); + s = QRinput_splitQRinputToStruct(input); + list = s->head; + e00 = list->input->head; + e01 = e00->next; + list = list->next; + e10 = list->input->head; + e11 = e10->next; + + assert_equal(e00->mode, QR_MODE_STRUCTURE, "Structure header is missing?"); + assert_equal(e01->mode, QR_MODE_8, "no data?!"); + assert_null(e01->next, "Input list is not terminated!\n"); + assert_equal(e10->mode, QR_MODE_STRUCTURE, "Structure header is missing?"); + assert_equal(e11->mode, QR_MODE_8, "no data?!"); + assert_null(e11->next, "Input list is not terminated!\n"); + + QRinput_free(input); + QRinput_Struct_free(s); + testFinish(); +} + +static void test_parity(void) +{ + QRinput *input; + QRinput_Struct *s; + const char *text = "an example of four Structured Append symbols,"; + const char *str[4] = { + "an example ", + "of four Str", + "uctured Appe", + "nd symbols,"}; + unsigned char p1, p2; + int i, len; + + testStart("Testing parity calc."); + s = QRinput_Struct_new(); + for(i=0; i<4; i++) { + input = QRinput_new2(1, QR_ECLEVEL_M); + QRinput_append(input, QR_MODE_8, strlen(str[i]), (unsigned char *)str[i]); + QRinput_Struct_appendInput(s, input); + } + QRinput_Struct_insertStructuredAppendHeaders(s); + p1 = s->parity; + + p2 = 0; + len = strlen(text); + for(i=0; i<len; i++) { + p2 ^= text[i]; + } + assert_equal(p1, p2, "Parity numbers didn't match. (%02x should be %02x).\n", p1, p2); + testFinish(); + QRinput_Struct_free(s); +} + +static void test_parity2(void) +{ + QRinput *input; + QRinput_Struct *s; + const char *text = "an example of four Structured Append symbols,"; + unsigned char p1, p2; + int i, len; + + testStart("Testing parity calc.(split)"); + input = QRinput_new2(1, QR_ECLEVEL_L); + QRinput_append(input, QR_MODE_8, strlen(text), (unsigned char *)text); + s = QRinput_splitQRinputToStruct(input); + p1 = s->parity; + + p2 = 0; + len = strlen(text); + for(i=0; i<len; i++) { + p2 ^= text[i]; + } + assert_equal(p1, p2, "Parity numbers didn't match. (%02x should be %02x).\n", p1, p2); + testFinish(); + QRinput_free(input); + QRinput_Struct_free(s); +} + +static void test_null_free(void) +{ + testStart("Testing free NULL pointers"); + assert_nothing(QRinput_free(NULL), "Check QRinput_free(NULL).\n"); + assert_nothing(QRinput_Struct_free(NULL), "Check QRinput_Struct_free(NULL).\n"); + testFinish(); +} + +static void fillCharacter(char *dest, char ch, int size) +{ + memset(dest, ch, size); + dest[size] = '\0'; +} + +static void checkEstimatedVersion(int ver, int mode) +{ + int estimatedVersion; + char data[7200]; + QRinput *input; + QRencodeMode hint; + int size1, size2; + static char *modeStr[4] = {"numeric", "alphanumeric", "8 bit data", "kanji"}; + static char ch[4] = {'0', 'A', 'a', '\x92'}; + + if(mode == QR_MODE_KANJI) { + hint = QR_MODE_KANJI; + size1 = maxCharacterLengths[ver - 1][mode] * 2; + size2 = size1 + 2; + } else { + hint = QR_MODE_8; + size1 = maxCharacterLengths[ver - 1][mode]; + size2 = size1 + 1; + } + + fillCharacter(data, ch[mode], size1); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(data, input, hint, 1); + estimatedVersion = QRinput_estimateVersion(input); + assert_equal(estimatedVersion, ver, "Estimated version %d is not equal to the expected version %d for %d %s sequence.\n", estimatedVersion, ver, maxCharacterLengths[ver - 1][mode], modeStr[mode]); + QRinput_free(input); + + fillCharacter(data, ch[mode], size2); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(data, input, hint, 1); + estimatedVersion = QRinput_estimateVersion(input); + assert_equal(estimatedVersion, ver + 1, "Estimated version %d is not equal to the expected version %d for %d %s sequence.\n", estimatedVersion, ver, maxCharacterLengths[ver - 1][mode] + 1, modeStr[mode]); + QRinput_free(input); +} + +static void test_estimateVersionBoundaryCheck(void) +{ + int ver; + testStart("Boundary check of estimateVersion"); + for(ver = 1; ver < QRSPEC_VERSION_MAX; ver++) { + checkEstimatedVersion(ver, QR_MODE_NUM); + checkEstimatedVersion(ver, QR_MODE_AN); + checkEstimatedVersion(ver, QR_MODE_8); + checkEstimatedVersion(ver, QR_MODE_KANJI); + } + testFinish(); +} + +static void test_QRinput_new_invalid(void) +{ + testStart("Invalid input to QRinput_new2()"); + QRinput *input; + + input = QRinput_new2(-1, QR_ECLEVEL_H); + assert_null(input, "QRinput_new2() returns non-null for invalid version (-1).\n"); + assert_equal(errno, EINVAL, "Error code is not EINVAL.\n"); + input = QRinput_new2(41, QR_ECLEVEL_H); + assert_null(input, "QRinput_new2() returns non-null for invalid version (41).\n"); + assert_equal(errno, EINVAL, "Error code is not EINVAL.\n"); + input = QRinput_new2(1, -1); + assert_null(input, "QRinput_new2() returns non-null for invalid level (-1).\n"); + assert_equal(errno, EINVAL, "Error code is not EINVAL.\n"); + input = QRinput_new2(1, 5); + assert_null(input, "QRinput_new2() returns non-null for invalid level (5).\n"); + assert_equal(errno, EINVAL, "Error code is not EINVAL.\n"); + testFinish(); +} + +static void test_QRinput_getErrorCorrectionLevel(void) +{ + testStart("Invalid input to QRinput_getErrorCorrectionLevel()"); + QRinput *input; + QRecLevel level; + + input = QRinput_new2(1, QR_ECLEVEL_H); + level = QRinput_getErrorCorrectionLevel(input); + assert_equal(level, QR_ECLEVEL_H, "QRinput_getErrorCorrectionLevel() fails to return expected level.\n"); + testFinish(); + QRinput_free(input); +} + +static void test_mqr_new(void) +{ + QRinput *input; + testStart("Testing QRinput_newMQR()."); + + input = QRinput_newMQR(0, QR_ECLEVEL_L); + assert_null(input, "Version 0 passed.\n"); + QRinput_free(input); + + input = QRinput_newMQR(5, QR_ECLEVEL_L); + assert_null(input, "Version 5 passed.\n"); + QRinput_free(input); + + input = QRinput_newMQR(1, QR_ECLEVEL_M); + assert_null(input, "Invalid ECLEVEL passed.\n"); + QRinput_free(input); + + input = QRinput_newMQR(1, QR_ECLEVEL_L); + assert_equal(input->version, 1, "QRinput.version was not as expected.\n"); + assert_equal(input->level, QR_ECLEVEL_L, "QRinput.version was not as expected.\n"); + QRinput_free(input); + + testFinish(); +} + +static void test_mqr_setversion(void) +{ + QRinput *input; + int ret; + testStart("Testing QRinput_setVersion() for MQR."); + + input = QRinput_newMQR(1, QR_ECLEVEL_L); + ret = QRinput_setVersion(input, 2); + assert_exp((ret < 0), "QRinput_setVersion should be denied.\n"); + QRinput_free(input); + + testFinish(); +} + +static void test_mqr_setlevel(void) +{ + QRinput *input; + int ret; + testStart("Testing QRinput_setErrorCorrectionLevel() for MQR."); + + input = QRinput_newMQR(1, QR_ECLEVEL_L); + ret = QRinput_setErrorCorrectionLevel(input, QR_ECLEVEL_M); + assert_exp((ret < 0), "QRinput_setErrorCorrectionLevel should be denied.\n"); + QRinput_free(input); + + testFinish(); +} + +static void test_paddingMQR(void) +{ + char *dataM1[] = {"65", "513", "5139", "51365"}; + char *correctM1[] = {"01010000010000000000", + "01110000000010000000", + "10010000000011001000", + "10110000000011000001"}; + char *dataM2[] = {"513513", "51351365"}; + char *correctM2[] = {"0 0110 1000000001 1000000001 0000000", + "0 1000 1000000001 1000000001 1000001"}; + int i, ret; + + testStart("Padding bit check of MQR. (only 0 padding)"); + for(i=0; i<4; i++) { + ret = encodeAndCheckBStream(1, 1, QR_ECLEVEL_L, QR_MODE_NUM, dataM1[i], correctM1[i]); + assert_zero(ret, "Number %s incorrectly encoded.\n", dataM1[i]); + } + for(i=0; i<2; i++) { + ret = encodeAndCheckBStream(1, 2, QR_ECLEVEL_M, QR_MODE_NUM, dataM2[i], correctM2[i]); + assert_zero(ret, "Number %s incorrectly encoded.\n", dataM2[i]); + } + testFinish(); +} + +static void test_padding2MQR(void) +{ + char *data[] = {"9", "513513", "513", "513"}; + int ver[] = {1, 2, 2, 3}; + char *correct[] = {"00110010 00000000 0000", + "0 0110 1000000001 1000000001 0000000 11101100", + "0 0011 1000000001 000000000 11101100 00010001", + "00 00011 1000000001 0000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 0000" + }; + int i, ret; + + testStart("Padding bit check. (1 or 2 padding bytes)"); + + for(i=0; i<4; i++) { + ret = encodeAndCheckBStream(1, ver[i], QR_ECLEVEL_L, QR_MODE_NUM, data[i], correct[i]); + assert_zero(ret, "Number %s incorrectly encoded.\n", data[i]); + } + testFinish(); +} + +static void test_textMQR(void) +{ + int version = 3; + QRecLevel level = QR_ECLEVEL_M; + char *str = "MICROQR"; + char *correct = {"01 0111 01111110000 01000110111 10001010010 011011 0000000 0000 11101100 0000"}; + int ret; + + testStart("Text encoding (Micro QR)"); + ret = encodeAndCheckBStream(1, version, level, QR_MODE_AN, str, correct); + assert_zero(ret, "AlphaNumeric string '%s' incorrectly encoded.\n", str); + testFinish(); +} + +static void test_ECIinvalid(void) +{ + QRinput *stream; + int ret; + + testStart("Appending invalid ECI header"); + stream = QRinput_new(); + ret = QRinput_appendECIheader(stream, 999999); + assert_zero(ret, "Valid ECI header rejected."); + ret = QRinput_appendECIheader(stream, 1000000); + assert_nonzero(ret, "Invalid ECI header accepted."); + QRinput_free(stream); + testFinish(); +} + +static void test_encodeECI(void) +{ + QRinput *input; + BitStream *bstream; + unsigned char str[] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; + char *correct = "0111 00001001 0100 00000101 10100001 10100010 10100011 10100100 10100101"; + int ret; + + testStart("Encoding characters with ECI header."); + input = QRinput_new(); + ret = QRinput_appendECIheader(input, 9); + assert_zero(ret, "Valid ECI header rejected.\n"); + + ret = QRinput_append(input, QR_MODE_8, 5, str); + assert_zero(ret, "Failed to append characters.\n"); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + assert_nonnull(bstream, "Failed to merge.\n"); + if(bstream != NULL) { + ret = ncmpBin(correct, bstream, 64); + assert_zero(ret, "Encodation of ECI header was invalid.\n"); + BitStream_free(bstream); + } + QRinput_free(input); + testFinish(); +} + +int main() +{ + int tests = 42; + testInit(tests); + + test_encodeNumeric(); + test_encodeNumeric2(); + test_encodeNumeric3(); + test_encodeNumeric_versionup(); + test_encode8(); + test_encode8_versionup(); + test_encodeAn(); + test_encodeAn2(); + test_encodeKanji(); + test_encodeNumericPadded(); + test_encodeNumericPadded2(); + test_encodeAnNum(); + test_padding(); + test_padding2(); + test_struct_listop(); + test_insertStructuredAppendHeader(); + test_insertStructuredAppendHeader_error(); + test_struct_insertStructuredAppendHeaders(); + test_lengthOfCode_num(); + test_lengthOfCode_kanji(); + test_splitentry(); + test_splitentry2(); + test_splitentry3(); + test_struct_split_example(); + test_struct_split_tooLarge(); + test_struct_split_invalidVersion(); + test_struct_singlestructure(); + test_parity(); + test_parity2(); + test_null_free(); + test_estimateVersionBoundaryCheck(); + test_QRinput_new_invalid(); + test_QRinput_getErrorCorrectionLevel(); + + test_mqr_new(); + test_mqr_setversion(); + test_mqr_setlevel(); + test_paddingMQR(); + test_padding2MQR(); + test_textMQR(); + + test_ECIinvalid(); + test_encodeECI(); + + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/test_qrspec.c b/genqrcode/tests/test_qrspec.c new file mode 100644 index 0000000000..15b7bbe9d2 --- /dev/null +++ b/genqrcode/tests/test_qrspec.c @@ -0,0 +1,319 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" +#include "../qrspec.h" +#include "../qrencode_inner.h" +#include "decoder.h" + +#ifndef SRCDIR +# define SRCDIR +#endif + +static void print_eccTable(void) +{ + int i, j; + int ecc; + int data; + int spec[5]; + + puts("\nPrinting ECC table.\n"); + for(i=1; i<=QRSPEC_VERSION_MAX; i++) { + printf("Version %2d\n", i); + for(j=0; j<4; j++) { + QRspec_getEccSpec(i, (QRecLevel)j, spec); + data = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec) + + QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec); + ecc = QRspec_rsBlockNum1(spec) * QRspec_rsEccCodes1(spec) + + QRspec_rsBlockNum2(spec) * QRspec_rsEccCodes2(spec); + printf("%3d\t", data); + printf("%3d\t", ecc); + printf("%2d\t", QRspec_rsBlockNum1(spec)); + printf("(%3d, %3d, %3d)\n", + QRspec_rsDataCodes1(spec) + QRspec_rsEccCodes1(spec), + QRspec_rsDataCodes1(spec), + QRspec_rsEccCodes1(spec)); + if(QRspec_rsBlockNum2(spec) > 0) { + printf("\t%2d\t", QRspec_rsBlockNum2(spec)); + printf("(%3d, %3d, %3d)\n", + QRspec_rsDataCodes2(spec) + QRspec_rsEccCodes2(spec), + QRspec_rsDataCodes2(spec), + QRspec_rsEccCodes2(spec)); + } + } + } +} + +static void test_eccTable(void) +{ + int i, j; + int ecc; + int data; + int err = 0; + int spec[5]; + + testStart("Checking ECC table."); + for(i=1; i<=QRSPEC_VERSION_MAX; i++) { + for(j=0; j<4; j++) { + QRspec_getEccSpec(i, (QRecLevel)j, spec); + data = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec) + + QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec); + ecc = QRspec_rsBlockNum1(spec) * QRspec_rsEccCodes1(spec) + + QRspec_rsBlockNum2(spec) * QRspec_rsEccCodes2(spec); + if(data + ecc != QRspec_getDataLength(i, (QRecLevel)j) + QRspec_getECCLength(i, (QRecLevel)j)) { + printf("Error in version %d, level %d: invalid size\n", i, j); + printf("%d %d %d %d %d %d\n", spec[0], spec[1], spec[2], spec[3], spec[4], spec[2]); + err++; + } + if(ecc != QRspec_getECCLength(i, (QRecLevel)j)) { + printf("Error in version %d, level %d: invalid data\n", i, j); + printf("%d %d %d %d %d %d\n", spec[0], spec[1], spec[2], spec[3], spec[4], spec[2]); + err++; + } + } + } + testEnd(err); +} + +static void test_eccTable2(void) +{ + int i; + int spec[5]; + + const int correct[7][6] = { + { 8, 1, 0, 2, 60, 38}, + { 8, 1, 1, 2, 61, 39}, + {24, 2, 0, 11, 54, 24}, + {24, 2, 1, 16, 55, 25}, + {32, 0, 0, 17, 145, 115}, + {40, 3, 0, 20, 45, 15}, + {40, 3, 1, 61, 46, 16}, + }; + + testStart("Checking ECC table(2)"); + for(i=0; i<7; i++) { + QRspec_getEccSpec(correct[i][0], (QRecLevel)correct[i][1], spec); + if(correct[i][2] == 0) { + assert_equal(QRspec_rsBlockNum1(spec), correct[i][3], + "Error in version %d, level %d. rsBlockNum1 was %d, expected %d.\n", + correct[i][0], correct[i][1], + QRspec_rsBlockNum1(spec), correct[i][3]); + assert_equal(QRspec_rsDataCodes1(spec) + QRspec_rsEccCodes1(spec), correct[i][4], + "Error in version %d, level %d. rsDataCodes1 + rsEccCodes1 was %d, expected %d.\n", + correct[i][0], correct[i][1], + QRspec_rsDataCodes1(spec) + QRspec_rsEccCodes1(spec), correct[i][4]); + assert_equal(QRspec_rsDataCodes1(spec), correct[i][5], + "Error in version %d, level %d. rsDataCodes1 was %d, expected %d.\n", + correct[i][0], correct[i][1], + QRspec_rsDataCodes1(spec), correct[i][5]); + } else { + assert_equal(QRspec_rsBlockNum2(spec), correct[i][3], + "Error in version %d, level %d. rsBlockNum2 was %d, expected %d.\n", + correct[i][0], correct[i][1], + QRspec_rsBlockNum2(spec), correct[i][3]); + assert_equal(QRspec_rsDataCodes2(spec) + QRspec_rsEccCodes2(spec), correct[i][4], + "Error in version %d, level %d. rsDataCodes2 + rsEccCodes2 was %d, expected %d.\n", + correct[i][0], correct[i][1], + QRspec_rsDataCodes2(spec) + QRspec_rsEccCodes2(spec), correct[i][4]); + assert_equal(QRspec_rsDataCodes2(spec), correct[i][5], + "Error in version %d, level %d. rsDataCodes2 was %d, expected %d.\n", + correct[i][0], correct[i][1], + QRspec_rsDataCodes2(spec), correct[i][5]); + } + } + testFinish(); +} + +static void test_newframe(void) +{ + unsigned char buf[QRSPEC_WIDTH_MAX * QRSPEC_WIDTH_MAX]; + int i, width; + size_t len; + FILE *fp; + unsigned char *frame; + QRcode *qrcode; + int version; + + testStart("Checking newly created frame."); + fp = fopen(SRCDIR "frame", "rb"); + if(fp == NULL) { + perror("Failed to open \"" SRCDIR "frame\":"); + abort(); + } + for(i=1; i<=QRSPEC_VERSION_MAX; i++) { + frame = QRspec_newFrame(i); + width = QRspec_getWidth(i); + len = fread(buf, 1, width * width, fp); + if((int)len != width * width) { + perror("Failed to read the pattern file:"); + abort(); + } + assert_zero(memcmp(frame, buf, len), "frame pattern mismatch (version %d)\n", i); + qrcode = QRcode_new(i, width, frame); + version = QRcode_decodeVersion(qrcode); + assert_equal(version, i, "Decoded version number is wrong: %d, expected %d.\n", version, i); + QRcode_free(qrcode); + } + + testFinish(); + fclose(fp); +} + +static void test_newframe_invalid(void) +{ + unsigned char *frame; + + testStart("Checking QRspec_newFrame with invalid version."); + frame = QRspec_newFrame(0); + assert_null(frame, "QRspec_newFrame(0) returns non-NULL."); + frame = QRspec_newFrame(QRSPEC_VERSION_MAX+1); + assert_null(frame, "QRspec_newFrame(0) returns non-NULL."); + testFinish(); +} + +#if 0 +/* This test is used to check positions of alignment pattern. See Appendix E + * (p.71) of JIS X0510:2004 and compare to the output. Before comment out + * this test, change the value of the pattern marker's center dot from 0xa1 + * to 0xb1 (QRspec_putAlignmentMarker() : finder). + */ +static void test_alignment(void) +{ + unsigned char *frame; + int i, x, y, width, c; + + testStart("Checking alignment pattern."); + for(i=2; i<=QRSPEC_VERSION_MAX; i++) { + printf("%2d", i); + frame = QRspec_newFrame(i); + width = QRspec_getWidth(i); + c = 0; + for(x=0; x<width * width; x++) { + if(frame[x] == 0xb1) { + c++; + } + } + printf("|%2d| 6", c); + y = width - 7; + for(x=0; x < width; x++) { + if(frame[y * width + x] == 0xb1) { + printf(", %3d", x); + } + } + printf("\n"); + free(frame); + } + testFinish(); +} +#endif + +static void test_verpat(void) +{ + int version; + unsigned int pattern; + int err = 0; + unsigned int data; + unsigned int code; + int i, c; + unsigned int mask; + + testStart("Checking version pattern."); + for(version=7; version <= QRSPEC_VERSION_MAX; version++) { + pattern = QRspec_getVersionPattern(version); + if((pattern >> 12) != (unsigned int)version) { + printf("Error in version %d.\n", version); + err++; + continue; + } + mask = 0x40; + for(i=0; mask != 0; i++) { + if(version & mask) break; + mask = mask >> 1; + } + c = 6 - i; + data = version << 12; + code = 0x1f25 << c; + mask = 0x40000 >> (6 - c); + for(i=0; i<=c; i++) { + if(mask & data) { + data ^= code; + } + code = code >> 1; + mask = mask >> 1; + } + data = (version << 12) | (data & 0xfff); + if(data != pattern) { + printf("Error in version %d\n", version); + err++; + } + } + testEnd(err); +} + +/* See Table 22 (p.45) and Appendix C (p. 65) of JIS X0510:2004 */ +static unsigned int levelIndicator[4] = {1, 0, 3, 2}; +static unsigned int calcFormatInfo(int mask, QRecLevel level) +{ + unsigned int data, ecc, b, code; + int i, c; + + data = (levelIndicator[level] << 13) | (mask << 10); + ecc = data; + b = 1 << 14; + for(i=0; b != 0; i++) { + if(ecc & b) break; + b = b >> 1; + } + c = 4 - i; + code = 0x537 << c ; //10100110111 + b = 1 << (10 + c); + for(i=0; i<=c; i++) { + if(b & ecc) { + ecc ^= code; + } + code = code >> 1; + b = b >> 1; + } + + return (data | ecc) ^ 0x5412; +} + +static void test_format(void) +{ + unsigned int format; + int i, j; + int err = 0; + + testStart("Format info test"); + for(i=0; i<4; i++) { + for(j=0; j<8; j++) { + format = calcFormatInfo(j, (QRecLevel)i); +// printf("0x%04x, ", format); + if(format != QRspec_getFormatInfo(j, (QRecLevel)i)) { + printf("Level %d, mask %x\n", i, j); + err++; + } + } +// printf("\n"); + } + testEnd(err); +} + +int main(int argc, char **argv) +{ + int tests = 6; + testInit(tests); + test_eccTable(); + test_eccTable2(); + test_newframe(); + test_newframe_invalid(); + //test_alignment(); + test_verpat(); + test_format(); + testReport(tests); + + if(argc > 1) { + print_eccTable(); + } + + return 0; +} diff --git a/genqrcode/tests/test_rs.c b/genqrcode/tests/test_rs.c new file mode 100644 index 0000000000..d0df44bfb3 --- /dev/null +++ b/genqrcode/tests/test_rs.c @@ -0,0 +1,126 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" +#include "../qrencode_inner.h" +#include "../qrspec.h" +#include "../mqrspec.h" +#include "../qrinput.h" +#include "../rsecc.h" +#include "decoder.h" +#include "rsecc_decoder.h" +#include "rscode.h" + +/* See pp. 73 of JIS X0510:2004 */ +void test_rscodeexample(void) +{ + QRinput *stream; + QRRawCode *code; + static const char str[9] = "01234567"; + static unsigned char correct[26] = { + 0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, + 0xec, 0x11, 0xec, 0x11, 0xa5, 0x24, 0xd4, 0xc1, 0xed, 0x36, 0xc7, 0x87, + 0x2c, 0x55}; + + testStart("RS ecc test"); + stream = QRinput_new(); + QRinput_append(stream, QR_MODE_NUM, 8, (unsigned char *)str); + QRinput_setErrorCorrectionLevel(stream, QR_ECLEVEL_M); + code = QRraw_new(stream); + + testEnd(memcmp(correct + 16, code->rsblock[0].ecc, 10)); + QRinput_free(stream); + QRraw_free(code); +} + +static void compareRS(unsigned char data[]) +{ + int i, j; + RS *rs; + int spec[5]; + int dl, el; + unsigned char ecc_expected[256], ecc_rscodec[256]; + + for(i = 1; i <= QRSPEC_VERSION_MAX; i++) { + for(j = QR_ECLEVEL_L; j <= QR_ECLEVEL_H; j++) { + QRspec_getEccSpec(i, (QRecLevel)j, spec); + dl = QRspec_rsDataCodes1(spec); + el = QRspec_rsEccCodes1(spec); + rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el); + RSECC_encode(dl, el, data, ecc_rscodec); + encode_rs_char(rs, data, ecc_expected); + assert_zero(memcmp(ecc_expected, ecc_rscodec, el), "Invalid ECC found: length %d.\n", el); + assert_zero(RSECC_decoder_checkSyndrome(dl, data, el, ecc_rscodec), "ECC error found."); + free_rs_char(rs); + + + dl = QRspec_rsDataCodes2(spec); + el = QRspec_rsEccCodes2(spec); + if(dl != 0) { + rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el); + RSECC_encode(dl, el, data, ecc_rscodec); + encode_rs_char(rs, data, ecc_expected); + assert_zero(memcmp(ecc_expected, ecc_rscodec, el), "Invalid ECC found: length %d.\n", el); + assert_zero(RSECC_decoder_checkSyndrome(dl, data, el, ecc_rscodec), "ECC error found."); + free_rs_char(rs); + } + } + } +} + +static void compareRSMQR(unsigned char data[]) +{ + int i, j; + RS *rs; + int dl, el; + unsigned char ecc_expected[256], ecc_rscodec[256]; + + for(i = 1; i <= MQRSPEC_VERSION_MAX; i++) { + for(j = QR_ECLEVEL_L; j <= QR_ECLEVEL_Q; j++) { + dl = MQRspec_getDataLength(i, (QRecLevel)j); + el = MQRspec_getECCLength(i, (QRecLevel)j); + if(dl != 0) { + rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el); + RSECC_encode(dl, el, data, ecc_rscodec); + encode_rs_char(rs, data, ecc_expected); + assert_zero(memcmp(ecc_expected, ecc_rscodec, el), "Invalid ECC found: length %d.\n", el); + assert_zero(RSECC_decoder_checkSyndrome(dl, data, el, ecc_rscodec), "ECC error found."); + free_rs_char(rs); + } + } + } +} + +void test_allQRSizeAndECCLevel(void) +{ + int i; + unsigned char data[256]; + + testStart("Comparing with KA9Q's code: all QR Code sizes and ECC levels"); + memset(data, 0, 256); + compareRS(data); + compareRSMQR(data); + memset(data, 0xaa, 256); + compareRS(data); + compareRSMQR(data); + memset(data, 0xff, 256); + compareRS(data); + compareRSMQR(data); + for(i=0; i<256; i++) { + data[i] = i; + } + compareRS(data); + compareRSMQR(data); + testFinish(); +} + +int main() +{ + RSECC_decoder_init(); + int tests = 2; + testInit(tests); + test_rscodeexample(); + test_allQRSizeAndECCLevel(); + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/test_split.c b/genqrcode/tests/test_split.c new file mode 100644 index 0000000000..e46f53514f --- /dev/null +++ b/genqrcode/tests/test_split.c @@ -0,0 +1,553 @@ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include "common.h" +#include "../qrspec.h" +#include "../qrinput.h" +#include "../mask.h" +#include "../split.h" +#include "../bitstream.h" + +static int inputTest(QRinput_List *list, const char *fmt, ...) +{ + va_list ap; + int size; + QRencodeMode mode; + int i, err = 0; + + va_start(ap, fmt); + i = 1; + while(*fmt) { + if(list == NULL) { + err = 1; + break; + } + size = va_arg(ap, int); + if(list->size != size) { + err = 1; + break; + } + + switch(*fmt++) { + case 'n': + mode = QR_MODE_NUM; + break; + case 'a': + mode = QR_MODE_AN; + break; + case 'k': + mode = QR_MODE_KANJI; + break; + case '8': + mode = QR_MODE_8; + break; + default: + return -1; + break; + } + if(list->mode != mode) { + err = 1; + break; + } + list = list->next; + i++; + } + va_end(ap); + if(list != NULL) { + err = 1; + } + if(err) { + return -i; + } + return 0; +} + +static int inputSize(QRinput *input) +{ + BitStream *bstream; + int size; + + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + size = BitStream_size(bstream); + BitStream_free(bstream); + + return size; +} + +static void test_split1(void) +{ + QRinput *input; + BitStream *bstream; + + testStart("Split test: null string"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("", input, QR_MODE_8, 0); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + testEndExp(BitStream_size(bstream) == 0); + QRinput_free(input); + BitStream_free(bstream); +} + +static void test_split2(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: single typed strings (num)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("0123", input, QR_MODE_8, 0); + list = input->head; + if(inputTest(list, "n", 4)) { + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: single typed strings (num2)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("12345678901234567890", input, QR_MODE_KANJI, 0); + list = input->head; + if(inputTest(list, "n", 20)) { + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_split3(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: single typed strings (an)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("ab:-E", input, QR_MODE_8, 0); + list = input->head; + if(inputTest(list, "a", 5)) { + printQRinputInfo(input); + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: num + an"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("0123abcde", input, QR_MODE_KANJI, 0); + list = input->head; + if(inputTest(list, "a", 9)) { + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: an + num + an"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("Ab345fg", input, QR_MODE_KANJI, 0); + list = input->head; + if(inputTest(list, "a", 7)) { + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_split4(void) +{ + QRinput *input; + QRinput *i1, *i2; + int s1, s2, size; +#define CHUNKA "ABCDEFGHIJK" +#define CHUNKB "123456" +#define CHUNKC "1234567" + + testStart("Split test: an and num entries"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(CHUNKA/**/CHUNKB, input, QR_MODE_8, 0); + i1 = QRinput_new(); + QRinput_append(i1, QR_MODE_AN, 17, (unsigned char *)CHUNKA/**/CHUNKB); + i2 = QRinput_new(); + QRinput_append(i2, QR_MODE_AN, 11, (unsigned char *)CHUNKA); + QRinput_append(i2, QR_MODE_NUM, 6, (unsigned char *)CHUNKB); + + size = inputSize(input); + s1 = inputSize(i1); + s2 = inputSize(i2); + testEndExp(size == ((s1 < s2)?s1:s2)); + QRinput_free(input); + QRinput_free(i1); + QRinput_free(i2); + + testStart("Split test: num and an entries"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(CHUNKB/**/CHUNKA, input, QR_MODE_8, 0); + i1 = QRinput_new(); + QRinput_append(i1, QR_MODE_AN, 17, (unsigned char *)CHUNKB/**/CHUNKA); + i2 = QRinput_new(); + QRinput_append(i2, QR_MODE_NUM, 6, (unsigned char *)CHUNKB); + QRinput_append(i2, QR_MODE_AN, 11, (unsigned char *)CHUNKA); + + size = inputSize(input); + s1 = inputSize(i1); + s2 = inputSize(i2); + testEndExp(size == ((s1 < s2)?s1:s2)); + QRinput_free(input); + QRinput_free(i1); + QRinput_free(i2); + + testStart("Split test: num and an entries (should be splitted)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(CHUNKC/**/CHUNKA, input, QR_MODE_8, 0); + i1 = QRinput_new(); + QRinput_append(i1, QR_MODE_AN, 18, (unsigned char *)CHUNKC/**/CHUNKA); + i2 = QRinput_new(); + QRinput_append(i2, QR_MODE_NUM, 7, (unsigned char *)CHUNKC); + QRinput_append(i2, QR_MODE_AN, 11, (unsigned char *)CHUNKA); + + size = inputSize(input); + s1 = inputSize(i1); + s2 = inputSize(i2); + testEndExp(size == ((s1 < s2)?s1:s2)); + QRinput_free(input); + QRinput_free(i1); + QRinput_free(i2); +} + +static void test_split5(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: bit, an, bit, num"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("\x82\xd9""abcdeabcdea\x82\xb0""123456", input, QR_MODE_8, 0); + list = input->head; + if(inputTest(list, "8a8n", 2, 11, 2, 6)) { + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_split6(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: kanji, an, kanji, num"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("\x82\xd9""abcdeabcdea\x82\xb0""123456", input, QR_MODE_KANJI, 0); + list = input->head; + if(inputTest(list, "kakn", 2, 11, 2, 6)) { + printQRinputInfo(input); + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_split7(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: an and num as bits"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("\x82\xd9""abcde\x82\xb0""12345", input, QR_MODE_8, 0); + list = input->head; + if(inputTest(list, "8n", 9, 5)) { + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_split8(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: terminated with a half of kanji code"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("\x82\xd9""abcdefgh\x82", input, QR_MODE_KANJI, 0); + list = input->head; + if(inputTest(list, "ka8", 2, 8, 1)) { + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_split3c(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: single typed strings (an, case-sensitive)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("ab:-E", input, QR_MODE_8, 1); + list = input->head; + if(inputTest(list, "8", 5)) { + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: num + an"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("0123abcde", input, QR_MODE_KANJI, 1); + list = input->head; + if(inputTest(list, "n8", 4, 5)) { + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: an + num + an"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("Ab345fg", input, QR_MODE_KANJI, 1); + list = input->head; + if(inputTest(list, "8", 7)) { + printQRinputInfo(input); + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_toupper(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: check dupAndToUpper (lower->upper)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("abcde", input, QR_MODE_8, 0); + list = input->head; + if(inputTest(list, "a", 5)) { + err++; + } + if(strncmp((char *)list->data, "ABCDE", list->size)) { + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: check dupAndToUpper (kanji)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("\x83n\x83q\x83t\x83w\x83z", input, QR_MODE_KANJI, 0); + list = input->head; + if(inputTest(list, "k", 10)) { + printQRinputInfo(input); + err++; + } + if(strncmp((char *)list->data, "\x83n\x83q\x83t\x83w\x83z", list->size)) { + err++; + } + testEnd(err); + QRinput_free(input); + + err = 0; + testStart("Split test: check dupAndToUpper (8bit)"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("\x83n\x83q\x83t\x83w\x83z", input, QR_MODE_8, 0); + list = input->head; + if(inputTest(list, "8", 10)) { + printQRinputInfo(input); + err++; + } + if(strncmp((char *)list->data, "\x83N\x83Q\x83T\x83W\x83Z", list->size)) { + err++; + } + testEnd(err); + QRinput_free(input); +} + +static void test_splitNum8(void) +{ + QRinput *input; + QRinput_List *list; + int err = 0; + + testStart("Split test: num and 8bit to 8bit"); + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput("1abcdefg", input, QR_MODE_8, 1); + list = input->head; + if(inputTest(list, "8", 8)) { + err++; + printQRinputInfo(input); + } + testEnd(err); + QRinput_free(input); +} + +static void test_splitAnNAn(void) +{ + QRinput *input1, *input2, *input3; + int s1, s2, s3; + char *strall = "326A80A9C5004C0875571F8B71C311F2F86"; + char *str1 = "326A80A9C5004C"; + char *str2 = "0875571"; + char *str3 = "F8B71C311F2F86"; + + testStart("Split test: An-N-An switching cost test"); + input1 = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(strall, input1, QR_MODE_8, 0); + + input2 = QRinput_new(); + QRinput_append(input2, QR_MODE_AN, 35, (unsigned char *)strall); + + input3 = QRinput_new(); + QRinput_append(input3, QR_MODE_AN, 14, (unsigned char *)str1); + QRinput_append(input3, QR_MODE_NUM, 7, (unsigned char *)str2); + QRinput_append(input3, QR_MODE_AN, 14, (unsigned char *)str3); + + s1 = inputSize(input1); + s2 = inputSize(input2); + s3 = inputSize(input3); + + assert_equal(s1, s2, "Incorrect split"); + assert_exp(s2 < s3, "Incorrect estimation"); + testFinish(); + QRinput_free(input1); + QRinput_free(input2); + QRinput_free(input3); +} + +static void test_splitAn8An(void) +{ + QRinput *input1, *input2, *input3; + int s1, s2, s3; + char *strall = "ABCDabcdefABCD"; + char *str1 = "ABCD"; + char *str2 = "abcdef"; + char *str3 = "ABCD"; + + testStart("Split test: An-8-An switching cost test"); + input1 = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(strall, input1, QR_MODE_8, 1); + + input2 = QRinput_new(); + QRinput_append(input2, QR_MODE_8, 14, (unsigned char *)strall); + + input3 = QRinput_new(); + QRinput_append(input3, QR_MODE_AN, 4, (unsigned char *)str1); + QRinput_append(input3, QR_MODE_8, 6, (unsigned char *)str2); + QRinput_append(input3, QR_MODE_AN, 4, (unsigned char *)str3); + + s1 = inputSize(input1); + s2 = inputSize(input2); + s3 = inputSize(input3); + + assert_equal(s1, s2, "Incorrect split"); + assert_exp(s2 < s3, "Incorrect estimation"); + testFinish(); + QRinput_free(input1); + QRinput_free(input2); + QRinput_free(input3); +} + +static void test_split8An8(void) +{ + QRinput *input1, *input2, *input3; + int s1, s2, s3; + char *strall = "abcABCDEFGHabc"; + char *str1 = "abc"; + char *str2 = "ABCDEFGH"; + char *str3 = "abc"; + + testStart("Split test: 8-An-8 switching cost test"); + input1 = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(strall, input1, QR_MODE_8, 1); + + input2 = QRinput_new(); + QRinput_append(input2, QR_MODE_8, 14, (unsigned char *)strall); + + input3 = QRinput_new(); + QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str1); + QRinput_append(input3, QR_MODE_AN, 8, (unsigned char *)str2); + QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str3); + + s1 = inputSize(input1); + s2 = inputSize(input2); + s3 = inputSize(input3); + + assert_equal(s1, s2, "Incorrect split"); + assert_exp(s2 < s3, "Incorrect estimation"); + testFinish(); + QRinput_free(input1); + QRinput_free(input2); + QRinput_free(input3); +} + +static void test_split8N8(void) +{ + QRinput *input1, *input2, *input3; + int s1, s2, s3; + char *strall = "abc1234abc"; + char *str1 = "abc"; + char *str2 = "1234"; + char *str3 = "abc"; + + testStart("Split test: 8-N-8 switching cost test"); + input1 = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(strall, input1, QR_MODE_8, 1); + + input2 = QRinput_new(); + QRinput_append(input2, QR_MODE_8, 10, (unsigned char *)strall); + + input3 = QRinput_new(); + QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str1); + QRinput_append(input3, QR_MODE_NUM, 4, (unsigned char *)str2); + QRinput_append(input3, QR_MODE_8, 3, (unsigned char *)str3); + + s1 = inputSize(input1); + s2 = inputSize(input2); + s3 = inputSize(input3); + + assert_equal(s1, s2, "Incorrect split"); + assert_exp(s2 < s3, "Incorrect estimation"); + testFinish(); + QRinput_free(input1); + QRinput_free(input2); + QRinput_free(input3); +} + +int main() +{ + int tests = 24; + testInit(tests); + test_split1(); + test_split2(); + test_split3(); + test_split4(); + test_split5(); + test_split6(); + test_split7(); + test_split8(); + test_split3c(); + test_toupper(); + test_splitNum8(); + test_splitAnNAn(); + test_splitAn8An(); + test_split8An8(); + test_split8N8(); + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/test_split_urls.c b/genqrcode/tests/test_split_urls.c new file mode 100644 index 0000000000..f1967ec0bd --- /dev/null +++ b/genqrcode/tests/test_split_urls.c @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "common.h" +#include "../qrinput.h" +#include "../qrencode_inner.h" +#include "../split.h" +#include "decoder.h" + +#include "URI_testset.inc" + +#if 0 +static void encodeURLandPrint(char *url) { + QRinput *input; + BitStream *bstream; + + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(url, input, QR_MODE_8, 1); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + + printf("{%zu,\"%s\"},\n", BitStream_size(bstream), url); + + QRinput_free(input); + BitStream_free(bstream); +} + +static void print_currentBitLength() { + struct TestSet *ts = testset; + + puts("struct TestSet {\n\tint expected_length;\n\tchar *url;\n};"); + puts("\nstruct TestSet testset[] = {"); + + while(ts->url != NULL) { + encodeURLandPrint(ts->url); + ts++; + } + + puts("{0,NULL}\n};"); +} +#endif + +static int encodeURLandCompare(char *url, size_t expected_length) { + QRinput *input; + BitStream *bstream; + int ret = 0; + + input = QRinput_new2(0, QR_ECLEVEL_L); + Split_splitStringToQRinput(url, input, QR_MODE_8, 1); + bstream = BitStream_new(); + QRinput_mergeBitStream(input, bstream); + + size_t length = BitStream_size(bstream); + if(length > expected_length) { + printf("The length of the encode stream is longer than expected: %zu over %zu\n", length, expected_length); + printQRinput(input); + + ret = 1; + } else if(length < expected_length) { + printf("The length of the encode stream is shorter than expected: %zu under %zu\n", length, expected_length); + printQRinput(input); + + ret = 1; + } + + QRinput_free(input); + BitStream_free(bstream); + + return ret; +} + +static void test_bitstream_length() { + struct TestSet *ts = testset; + int err = 0; + + testStart("Split_URL test: compare bitstream length"); + while(ts->url != NULL) { + err += encodeURLandCompare(ts->url, ts->expected_length); + ts++; + } + testEnd(err); +} + +int main() +{ + int tests = 1; + testInit(tests); + test_bitstream_length(); + testReport(tests); + + return 0; +} diff --git a/genqrcode/tests/view_qrcode.c b/genqrcode/tests/view_qrcode.c new file mode 100644 index 0000000000..f9d1bea96b --- /dev/null +++ b/genqrcode/tests/view_qrcode.c @@ -0,0 +1,641 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <SDL.h> +#include <getopt.h> +#include <errno.h> +#include "../config.h" +#include "../qrspec.h" +#include "../qrinput.h" +#include "../split.h" +#include "../qrencode_inner.h" + +static SDL_Window *window; +static SDL_Renderer *renderer; +static SDL_Texture *texture = NULL; +static SDL_Surface *surface = NULL; +static int casesensitive = 1; +static int eightbit = 0; +static int version = 0; +static int size = 4; +static int margin = -1; +static int structured = 0; +static int micro = 0; +static int colorize = 0; +static QRecLevel level = QR_ECLEVEL_L; +static QRencodeMode hint = QR_MODE_8; + +static char **textv; +static int textc; + +static const struct option options[] = { + {"help" , no_argument , NULL, 'h'}, + {"level" , required_argument, NULL, 'l'}, + {"size" , required_argument, NULL, 's'}, + {"symversion" , required_argument, NULL, 'v'}, + {"margin" , required_argument, NULL, 'm'}, + {"structured" , no_argument , NULL, 'S'}, + {"kanji" , no_argument , NULL, 'k'}, + {"casesensitive", no_argument , NULL, 'c'}, + {"ignorecase" , no_argument , NULL, 'i'}, + {"8bit" , no_argument , NULL, '8'}, + {"micro" , no_argument , NULL, 'M'}, + {"version" , no_argument , NULL, 'V'}, + {NULL, 0, NULL, 0} +}; + +static char *optstring = "hl:s:v:m:Skci8MV"; + +static char levelChar[4] = {'L', 'M', 'Q', 'H'}; +static void usage(int help, int longopt) +{ + fprintf(stderr, +"view_qrcode version %s\n" +"Copyright (C) 2008, 2009, 2010 Kentaro Fukuchi\n", VERSION); + if(help) { + if(longopt) { + fprintf(stderr, +"Usage: view_qrcode [OPTION]... [STRING]\n" +"Encode input data in a QR Code and display.\n\n" +" -h, --help display the help message. -h displays only the help of short\n" +" options.\n\n" +" -s NUMBER, --size=NUMBER\n" +" specify module size in dots (pixels). (default=3)\n\n" +" -l {LMQH}, --level={LMQH}\n" +" specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n\n" +" -v NUMBER, --symversion=NUMBER\n" +" specify the version of the symbol. See SYMBOL VERSIONS for more\n" +" information. (default=auto)\n\n" +" -m NUMBER, --margin=NUMBER\n" +" specify the width of the margins. (default=4 (2 for Micro QR)))\n\n" +" -S, --structured\n" +" make structured symbols. Version must be specified.\n\n" +" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n" +" -c, --casesensitive\n" +" encode lower-case alphabet characters in 8-bit mode. (default)\n\n" +" -i, --ignorecase\n" +" ignore case distinctions and use only upper-case characters.\n\n" +" -8, --8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n" +" -M, --micro encode in a Micro QR Code. (experimental)\n\n" +" -V, --version\n" +" display the version number and copyrights of the qrencode.\n\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n\n" +"*SYMBOL VERSIONS\n" +" The symbol versions of QR Code range from Version 1 to Version\n" +" 40. Each version has a different module configuration or number\n" +" of modules, ranging from Version 1 (21 x 21 modules) up to\n" +" Version 40 (177 x 177 modules). Each higher version number\n" +" comprises 4 additional modules per side by default. See\n" +" http://www.qrcode.com/en/about/version.html for a detailed\n" +" version list.\n" + ); + } else { + fprintf(stderr, +"Usage: view_qrcode [OPTION]... [STRING]\n" +"Encode input data in a QR Code and display.\n\n" +" -h display this message.\n" +" --help display the usage of long options.\n" +" -s NUMBER specify module size in dots (pixels). (default=3)\n" +" -l {LMQH} specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n" +" -v NUMBER specify the version of the symbol. (default=auto)\n" +" -m NUMBER specify the width of the margins. (default=4 (2 for Micro))\n" +" -S make structured symbols. Version must be specified.\n" +" -k assume that the input text contains kanji (shift-jis).\n" +" -c encode lower-case alphabet characters in 8-bit mode. (default)\n" +" -i ignore case distinctions and use only upper-case characters.\n" +" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n" +" -M encode in a Micro QR Code.\n" +" -V display the version number and copyrights of the qrencode.\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n" + ); + } + } +} + +#define MAX_DATA_SIZE (7090 * 16) /* from the specification */ +static unsigned char *readStdin(int *length) +{ + unsigned char *buffer; + int ret; + + buffer = (unsigned char *)malloc(MAX_DATA_SIZE + 1); + if(buffer == NULL) { + fprintf(stderr, "Memory allocation failed.\n"); + exit(EXIT_FAILURE); + } + + ret = fread(buffer, 1, MAX_DATA_SIZE, stdin); + if(ret == 0) { + fprintf(stderr, "No input data.\n"); + exit(EXIT_FAILURE); + } + if(feof(stdin) == 0) { + fprintf(stderr, "Input data is too large.\n"); + exit(EXIT_FAILURE); + } + + buffer[ret] = '\0'; + *length = ret; + + return buffer; +} + +static void draw_QRcode(QRcode *qrcode, int ox, int oy) +{ + int x, y, width; + unsigned char *p; + SDL_Rect rect; + Uint32 color[8]; + int col; + + color[0] = SDL_MapRGBA(surface->format, 255, 255, 255, 255); + color[1] = SDL_MapRGBA(surface->format, 0, 0, 0, 255); + color[2] = SDL_MapRGBA(surface->format, 192, 192, 255, 255); + color[3] = SDL_MapRGBA(surface->format, 0, 0, 64, 255); + color[4] = SDL_MapRGBA(surface->format, 255, 255, 192, 255); + color[5] = SDL_MapRGBA(surface->format, 64, 64, 0, 255); + color[6] = SDL_MapRGBA(surface->format, 255, 192, 192, 255); + color[7] = SDL_MapRGBA(surface->format, 64, 0, 0, 255); + + ox += margin * size; + oy += margin * size; + width = qrcode->width; + p = qrcode->data; + for(y=0; y<width; y++) { + for(x=0; x<width; x++) { + rect.x = ox + x * size; + rect.y = oy + y * size; + rect.w = size; + rect.h = size; + if(!colorize) { + col = 0; + } else { + if(*p & 0x80) { + col = 6; + } else if(*p & 0x02) { + col = 4; + } else { + col = 2; + } + } + col += (*p & 1); + SDL_FillRect(surface, &rect, color[col]); + p++; + } + } +} + +static void draw_singleQRcode(QRinput *stream, int mask) +{ + QRcode *qrcode; + int width; + + QRinput_setVersionAndErrorCorrectionLevel(stream, version, level); + if(micro) { + qrcode = QRcode_encodeMaskMQR(stream, mask); + } else { + qrcode = QRcode_encodeMask(stream, mask); + } + if(qrcode == NULL) { + width = (11 + margin * 2) * size; + fprintf(stderr, "Input data does not fit to this setting.\n"); + } else { + version = qrcode->version; + width = (qrcode->width + margin * 2) * size; + } + + SDL_SetWindowSize(window, width, width); + if(surface != NULL) { + SDL_FreeSurface(surface); + } + surface = SDL_CreateRGBSurface(0, width, width, 32, 0, 0, 0, 0); + SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255)); + if(qrcode) { + draw_QRcode(qrcode, 0, 0); + } + if(texture != NULL) { + SDL_DestroyTexture(texture); + } + texture = SDL_CreateTextureFromSurface(renderer, surface); + QRcode_free(qrcode); +} + +static void draw_structuredQRcode(QRinput_Struct *s) +{ + int i, w, h, n, x, y; + int swidth; + QRcode_List *qrcodes, *p; + + qrcodes = QRcode_encodeInputStructured(s); + if(qrcodes == NULL) return; + + swidth = (qrcodes->code->width + margin * 2) * size; + n = QRcode_List_size(qrcodes); + w = (n < 4)?n:4; + h = (n - 1) / 4 + 1; + + SDL_SetWindowSize(window, swidth * w, swidth * h); + if(surface != NULL) { + SDL_FreeSurface(surface); + } + surface = SDL_CreateRGBSurface(0, swidth * w, swidth * h, 32, 0, 0, 0, 0); + SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, 255, 255, 255, 255)); + + p = qrcodes; + for(i=0; i<n; i++) { + x = (i % 4) * swidth; + y = (i / 4) * swidth; + draw_QRcode(p->code, x, y); + p = p->next; + } + if(texture != NULL) { + SDL_DestroyTexture(texture); + } + texture = SDL_CreateTextureFromSurface(renderer, surface); + QRcode_List_free(qrcodes); +} + +static void draw_structuredQRcodeFromText(int argc, char **argv) +{ + QRinput_Struct *s; + QRinput *input; + int i, ret; + + s = QRinput_Struct_new(); + if(s == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + for(i=0; i<argc; i++) { + input = QRinput_new2(version, level); + if(input == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, strlen(argv[i]), (unsigned char *)argv[i]); + } else { + ret = Split_splitStringToQRinput(argv[i], input, hint, casesensitive); + } + if(ret < 0) { + perror("Encoding the input string"); + exit(EXIT_FAILURE); + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) { + perror("Encoding the input string"); + exit(EXIT_FAILURE); + } + } + ret = QRinput_Struct_insertStructuredAppendHeaders(s); + if(ret < 0) { + fprintf(stderr, "Too many inputs.\n"); + } + + draw_structuredQRcode(s); + QRinput_Struct_free(s); +} + +static void draw_structuredQRcodeFromQRinput(QRinput *stream) +{ + QRinput_Struct *s; + + QRinput_setVersion(stream, version); + QRinput_setErrorCorrectionLevel(stream, level); + s = QRinput_splitQRinputToStruct(stream); + if(s != NULL) { + draw_structuredQRcode(s); + QRinput_Struct_free(s); + } else { + fprintf(stderr, "Input data is too large for this setting.\n"); + } +} + +static void view(int mode, QRinput *input) +{ + int flag = 1; + int mask = -1; + SDL_Event event; + int loop; + int codeChanged = 1; + + while(flag) { + if(codeChanged) { + if(mode) { + draw_structuredQRcodeFromText(textc, textv); + } else { + if(structured) { + draw_structuredQRcodeFromQRinput(input); + } else { + draw_singleQRcode(input, mask); + } + } + if(mode || structured) { + printf("Version %d, Level %c.\n", version, levelChar[level]); + } else { + printf("Version %d, Level %c, Mask %d.\n", version, levelChar[level], mask); + } + } + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + loop = 1; + codeChanged = 0; + while(loop) { + SDL_WaitEvent(&event); + if(event.type == SDL_KEYDOWN) { + codeChanged = 1; + switch(event.key.keysym.sym) { + case SDLK_RIGHT: + version++; + if(version > QRSPEC_VERSION_MAX) + version = QRSPEC_VERSION_MAX; + loop = 0; + break; + case SDLK_LEFT: + version--; + if(version < 1) + version = 1; + loop = 0; + break; + case SDLK_UP: + size++; + loop = 0; + break; + case SDLK_DOWN: + size--; + if(size < 1) size = 1; + loop = 0; + break; + case SDLK_0: + case SDLK_1: + case SDLK_2: + case SDLK_3: + case SDLK_4: + case SDLK_5: + case SDLK_6: + case SDLK_7: + if(!mode && !structured) { + mask = (event.key.keysym.sym - SDLK_0); + loop = 0; + } + break; + case SDLK_8: + if(!mode && !structured) { + mask = -1; + loop = 0; + } + break; + case SDLK_9: + if(!mode && !structured) { + mask = -2; + loop = 0; + } + break; + case SDLK_l: + level = QR_ECLEVEL_L; + loop = 0; + break; + case SDLK_m: + level = QR_ECLEVEL_M; + loop = 0; + break; + case SDLK_h: + level = QR_ECLEVEL_H; + loop = 0; + break; + case SDLK_q: + level = QR_ECLEVEL_Q; + loop = 0; + break; + case SDLK_c: + colorize ^= 1; + loop = 0; + break; + case SDLK_ESCAPE: + loop = 0; + flag = 0; + break; + default: + break; + } + if(event.type == SDL_QUIT) { + loop = 0; + flag = 0; + } + } + if (event.type == SDL_WINDOWEVENT) { + switch (event.window.event) { + case SDL_WINDOWEVENT_SHOWN: + case SDL_WINDOWEVENT_EXPOSED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + case SDL_WINDOWEVENT_RESIZED: + loop = 0; + break; + default: + break; + } + } + } + } +} + +static void view_simple(const unsigned char *str, int length) +{ + QRinput *input; + int ret; + + if(micro) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) { + fprintf(stderr, "Memory allocation error.\n"); + exit(EXIT_FAILURE); + } + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, length, str); + } else { + ret = Split_splitStringToQRinput((char *)str, input, hint, casesensitive); + } + if(ret < 0) { + perror("Encoding the input string"); + exit(EXIT_FAILURE); + } + + view(0, input); + + QRinput_free(input); +} + +static void view_multiText(char **argv, int argc) +{ + textc = argc; + textv = argv; + + view(1, NULL); +} + +int main(int argc, char **argv) +{ + int opt, lindex = -1; + unsigned char *intext = NULL; + int length = 0; + int ret; + + while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) { + switch(opt) { + case 'h': + if(lindex == 0) { + usage(1, 1); + } else { + usage(1, 0); + } + exit(EXIT_SUCCESS); + break; + case 's': + size = atoi(optarg); + if(size <= 0) { + fprintf(stderr, "Invalid size: %d\n", size); + exit(EXIT_FAILURE); + } + break; + case 'v': + version = atoi(optarg); + if(version < 0) { + fprintf(stderr, "Invalid version: %d\n", version); + exit(EXIT_FAILURE); + } + break; + case 'l': + switch(*optarg) { + case 'l': + case 'L': + level = QR_ECLEVEL_L; + break; + case 'm': + case 'M': + level = QR_ECLEVEL_M; + break; + case 'q': + case 'Q': + level = QR_ECLEVEL_Q; + break; + case 'h': + case 'H': + level = QR_ECLEVEL_H; + break; + default: + fprintf(stderr, "Invalid level: %s\n", optarg); + exit(EXIT_FAILURE); + break; + } + break; + case 'm': + margin = atoi(optarg); + if(margin < 0) { + fprintf(stderr, "Invalid margin: %d\n", margin); + exit(EXIT_FAILURE); + } + break; + case 'S': + structured = 1; + case 'k': + hint = QR_MODE_KANJI; + break; + case 'c': + casesensitive = 1; + break; + case 'i': + casesensitive = 0; + break; + case '8': + eightbit = 1; + break; + case 'M': + micro = 1; + break; + case 'V': + usage(0, 0); + exit(EXIT_SUCCESS); + break; + default: + fprintf(stderr, "Try `view_qrcode --help' for more information.\n"); + exit(EXIT_FAILURE); + break; + } + } + + if(argc == 1) { + usage(1, 0); + exit(EXIT_SUCCESS); + } + + if(optind < argc) { + intext = (unsigned char *)argv[optind]; + length = strlen((char *)intext); + } + if(intext == NULL) { + intext = readStdin(&length); + } + + if(micro && version > MQRSPEC_VERSION_MAX) { + fprintf(stderr, "Version should be less or equal to %d.\n", MQRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } else if(!micro && version > QRSPEC_VERSION_MAX) { + fprintf(stderr, "Version should be less or equal to %d.\n", QRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } + + if(margin < 0) { + if(micro) { + margin = 2; + } else { + margin = 4; + } + } + + if(micro) { + if(version == 0) { + fprintf(stderr, "Version must be specified to encode a Micro QR Code symbol.\n"); + exit(EXIT_FAILURE); + } + if(structured) { + fprintf(stderr, "Micro QR Code does not support structured symbols.\n"); + exit(EXIT_FAILURE); + } + } + + if(structured && version == 0) { + fprintf(stderr, "Version must be specified to encode structured symbols.\n"); + exit(EXIT_FAILURE); + } + + if(SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "Failed initializing SDL: %s\n", SDL_GetError()); + return -1; + } + + ret = SDL_CreateWindowAndRenderer(100, 100, SDL_WINDOW_SHOWN, &window, &renderer); + if(ret < 0) { + fprintf(stderr, "Failed to create a window: %s\n", SDL_GetError()); + return -1; + } + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + if(structured && (argc - optind > 1)) { + view_multiText(argv + optind, argc - optind); + } else { + view_simple(intext, length); + } + + SDL_Quit(); + + return 0; +} diff --git a/genqrcode/use/config.rpath b/genqrcode/use/config.rpath new file mode 100755 index 0000000000..98183ff2f2 --- /dev/null +++ b/genqrcode/use/config.rpath @@ -0,0 +1,684 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2016 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + nagfor*) + wl='-Wl,-Wl,,' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + xl* | bgxl* | bgf* | mpixl*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + wl= + ;; + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + newsos6) + ;; + *nto* | *qnx*) + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + wl='-Qoption ld ' + ;; + *) + wl='-Wl,' + ;; + esac + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + case "$host_cpu" in + powerpc) + ;; + m68k) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + haiku*) + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + case "$host_cpu" in + powerpc) + ;; + m68k) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then + : + else + ld_shlibs=no + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd2.[01]*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + *nto* | *qnx*) + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + case "$host_cpu" in + powerpc*) + library_names_spec='$libname$shrext' ;; + m68k) + library_names_spec='$libname.a' ;; + esac + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd[23].*) + library_names_spec='$libname$shrext$versuffix' + ;; + freebsd* | dragonfly*) + library_names_spec='$libname$shrext' + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + haiku*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + *nto* | *qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + tpf*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF + +# How to pass a linker flag through the compiler. +wl="$escaped_wl" + +# Static library suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally "so"). +shlibext="$shlibext" + +# Format of library name prefix. +libname_spec="$escaped_libname_spec" + +# Library names that the linker finds when passed -lNAME. +library_names_spec="$escaped_library_names_spec" + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct="$hardcode_direct" + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L="$hardcode_minus_L" + +EOF |
