Import Upstream version 4.1.1
This commit is contained in:
commit
472578fa9f
|
@ -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 "------------------------------------------------------------ ")
|
|
@ -0,0 +1,510 @@
|
|||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin St, 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 St, 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!
|
||||
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,332 @@
|
|||
libqrencode NEWS - Overview of changes
|
||||
======================================
|
||||
|
||||
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.
|
|
@ -0,0 +1,224 @@
|
|||
libqrencode - a fast and compact QR Code encoding library
|
||||
|
||||
|
||||
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
|
||||
- libpng12-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 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.
|
||||
* 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
|
||||
- bug report / suggestion / typo fixes
|
|
@ -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.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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()
|
|
@ -0,0 +1,102 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define if you have the iconv() function and it works. */
|
||||
#undef HAVE_ICONV
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if using pthread is enabled. */
|
||||
#undef HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if using libpng is enabled. */
|
||||
#undef HAVE_PNG
|
||||
|
||||
/* Define to 1 if using SDL is enabled. */
|
||||
#undef HAVE_SDL
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Major version number */
|
||||
#undef MAJOR_VERSION
|
||||
|
||||
/* Micro version number */
|
||||
#undef MICRO_VERSION
|
||||
|
||||
/* Minor version number */
|
||||
#undef MINOR_VERSION
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to 'static' if no test programs will be compiled. */
|
||||
#define STATIC_IN_RELEASE static
|
||||
#undef WITH_TESTS
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,167 @@
|
|||
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-mudflap
|
||||
AC_ARG_ENABLE([mudflap], [AS_HELP_STRING([--enable-mudflap], [generate extra code to check memory leaks [default=no]])],
|
||||
[], [enable_mudflap=no])
|
||||
|
||||
if test x$enable_mudflap = xyes; then
|
||||
if test x$enable_thread_safety = xyes; then
|
||||
CFLAGS="$CFLAGS -fmudflapth"
|
||||
LDFLAGS="$LDFLAGS -lmudflapth"
|
||||
else
|
||||
CFLAGS="$CFLAGS -fmudflap"
|
||||
LDFLAGS="$LDFLAGS -lmudflap"
|
||||
fi
|
||||
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 ""
|
|
@ -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}
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Demerit coefficients.
|
||||
* See Section 8.8.2, pp.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 demerit = 0;
|
||||
int fact;
|
||||
|
||||
for(i = 0; i < length; i++) {
|
||||
if(runLength[i] >= 5) {
|
||||
demerit += 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) {
|
||||
demerit += N3;
|
||||
//n3 += N3;
|
||||
} else if(i+4 >= length || runLength[i+3] >= 4 * fact) {
|
||||
demerit += N3;
|
||||
//n3 += N3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
STATIC_IN_RELEASE int Mask_calcN2(int width, unsigned char *frame)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char *p;
|
||||
unsigned char b22, w22;
|
||||
int demerit = 0;
|
||||
|
||||
p = frame + width + 1;
|
||||
for(y = 1; y < width; y++) {
|
||||
for(x = 1; x < width; x++) {
|
||||
b22 = p[0] & p[-1] & p[-width] & p [-width-1];
|
||||
w22 = p[0] | p[-1] | p[-width] | p [-width-1];
|
||||
if((b22 | (w22 ^ 1))&1) {
|
||||
demerit += N2;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
STATIC_IN_RELEASE int Mask_calcRunLengthH(int width, unsigned char *frame, int *runLength)
|
||||
{
|
||||
int head;
|
||||
int i;
|
||||
unsigned char prev;
|
||||
|
||||
if(frame[0] & 1) {
|
||||
runLength[0] = -1;
|
||||
head = 1;
|
||||
} else {
|
||||
head = 0;
|
||||
}
|
||||
runLength[head] = 1;
|
||||
prev = frame[0];
|
||||
|
||||
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;
|
||||
|
||||
if(frame[0] & 1) {
|
||||
runLength[0] = -1;
|
||||
head = 1;
|
||||
} else {
|
||||
head = 0;
|
||||
}
|
||||
runLength[head] = 1;
|
||||
prev = frame[0];
|
||||
|
||||
for(i = 1; i < width; i++) {
|
||||
if((frame[i * width] ^ prev) & 1) {
|
||||
head++;
|
||||
runLength[head] = 1;
|
||||
prev = frame[i * width];
|
||||
} else {
|
||||
runLength[head]++;
|
||||
}
|
||||
}
|
||||
|
||||
return head + 1;
|
||||
}
|
||||
|
||||
STATIC_IN_RELEASE int Mask_evaluateSymbol(int width, unsigned char *frame)
|
||||
{
|
||||
int x, y;
|
||||
int demerit = 0;
|
||||
int runLength[QRSPEC_WIDTH_MAX + 1];
|
||||
int length;
|
||||
|
||||
demerit += Mask_calcN2(width, frame);
|
||||
|
||||
for(y = 0; y < width; y++) {
|
||||
length = Mask_calcRunLengthH(width, frame + y * width, runLength);
|
||||
demerit += Mask_calcN1N3(length, runLength);
|
||||
}
|
||||
|
||||
for(x = 0; x < width; x++) {
|
||||
length = Mask_calcRunLengthV(width, frame + x, runLength);
|
||||
demerit += Mask_calcN1N3(length, runLength);
|
||||
}
|
||||
|
||||
return demerit;
|
||||
}
|
||||
|
||||
unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level)
|
||||
{
|
||||
int i;
|
||||
unsigned char *mask, *bestMask;
|
||||
int minDemerit = INT_MAX;
|
||||
int blacks;
|
||||
int bratio;
|
||||
int demerit;
|
||||
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;
|
||||
demerit = 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) */
|
||||
demerit = (abs(bratio - 50) / 5) * N4;
|
||||
// n4 = demerit;
|
||||
demerit += Mask_evaluateSymbol(width, mask);
|
||||
// printf("(%d,%d,%d,%d)=%d\n", n1, n2, n3 ,n4, demerit);
|
||||
if(demerit < minDemerit) {
|
||||
minDemerit = demerit;
|
||||
memcpy(bestMask, mask, (size_t)w2);
|
||||
}
|
||||
}
|
||||
free(mask);
|
||||
return bestMask;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 (pp.106) and Table 8 (pp.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 (pp.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. (pp.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
|
||||
* @param 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);
|
||||
}
|
|
@ -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, pp.107.
|
||||
*/
|
||||
#define MQRSPEC_MODEID_NUM 0
|
||||
#define MQRSPEC_MODEID_AN 1
|
||||
#define MQRSPEC_MODEID_8 2
|
||||
#define MQRSPEC_MODEID_KANJI 3
|
||||
|
||||
#endif /* MQRSPEC_H */
|
|
@ -0,0 +1,136 @@
|
|||
.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)
|
||||
.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 Kentaro Fukuchi.
|
|
@ -0,0 +1,938 @@
|
|||
/*
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* 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"
|
||||
#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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
#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((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((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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned char QRcode_parity(const char *str, int size)
|
||||
{
|
||||
unsigned char parity = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < size; i++) {
|
||||
parity ^= str[i];
|
||||
}
|
||||
|
||||
return parity;
|
||||
}
|
||||
#endif
|
||||
|
||||
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((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), (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), (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;
|
||||
}
|
|
@ -0,0 +1,568 @@
|
|||
/**
|
||||
* qrencode - QR Code encoder
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/** \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.
|
||||
*
|
||||
* \section structured Structured append
|
||||
* Libqrencode can generate "Structured-appended" symbols that enables to split
|
||||
* a large data set into mulitple 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 functions 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 indeicate 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 indeicate 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 indeicate 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
|
||||
*/
|
||||
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 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 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 a string that identifies the library version.
|
||||
* @param major_version major version number
|
||||
* @param minor_version minor version number
|
||||
* @param micro_version 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 */
|
|
@ -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 */
|
|
@ -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, pp.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, unsigned char parity);
|
||||
#endif
|
||||
|
||||
#endif /* QRINPUT_H */
|
|
@ -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 (pp.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 (pp.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
|
||||
* @param 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 (pp.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
|
||||
* @param 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);
|
||||
}
|
|
@ -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, pp.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 */
|
|
@ -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 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];
|
||||
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] = b;
|
||||
aindex[b] = 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;
|
||||
}
|
|
@ -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 */
|
|
@ -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, (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, (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, (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, (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;
|
||||
}
|
|
@ -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 */
|
|
@ -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()
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,290 @@
|
|||
#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 tests)
|
||||
{
|
||||
printf("1..%d\n", tests);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int testNum(void)
|
||||
{
|
||||
return tests;
|
||||
}
|
||||
|
||||
void printBinary(unsigned char *data, int length)
|
||||
{
|
||||
int 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
|
|
@ -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, int length);
|
||||
void printBstream(BitStream *bstream);
|
||||
|
||||
void show_QRcode(QRcode *qrcode);
|
||||
|
||||
#endif /* COMMON_H__ */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
#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)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char c;
|
||||
int 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: %d bytes\n", chunk->size);
|
||||
dumpNum(chunk);
|
||||
break;
|
||||
case QR_MODE_AN:
|
||||
printf("AlphaNumeric: %d bytes\n", chunk->size);
|
||||
dumpAn(chunk);
|
||||
break;
|
||||
case QR_MODE_8:
|
||||
printf("8-bit data: %d bytes\n", chunk->size);
|
||||
dump8(chunk);
|
||||
break;
|
||||
case QR_MODE_KANJI:
|
||||
printf("Kanji: %d bytes\n", chunk->size);
|
||||
dumpKanji(chunk);
|
||||
break;
|
||||
default:
|
||||
printf("Invalid or reserved: %d 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 + 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;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef DATACHUNK_H
|
||||
#define DATACHUNK_H
|
||||
|
||||
#include "../qrencode.h"
|
||||
|
||||
typedef struct _DataChunk {
|
||||
QRencodeMode mode;
|
||||
int size;
|
||||
int bits;
|
||||
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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
Binary file not shown.
|
@ -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 (500 symbols for each)");
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
timerStop();
|
||||
}
|
||||
|
||||
static void prof_ver31to40(void)
|
||||
{
|
||||
QRcode *code;
|
||||
int i;
|
||||
int version;
|
||||
static const char *data = "This is test.";
|
||||
|
||||
timerStart("Version 31 - 40 (50 symbols for each)");
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
timerStop();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
prof_ver1to10();
|
||||
prof_ver31to40();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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] = b;
|
||||
aindex[b] = 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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef RSECC_DECODER_H
|
||||
#define RSECC_DECODER_H
|
||||
|
||||
void RSECC_decoder_init();
|
||||
int RSECC_decoder_checkSyndrome(int dl, unsigned char *data, int el, unsigned char *ecc);
|
||||
|
||||
#endif /* RSECC_DECODER_H */
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh -e
|
||||
. ./test_basic.sh
|
||||
./test_configure.sh
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh -e
|
||||
./test_bitstream
|
||||
./test_estimatebit
|
||||
./test_qrencode
|
||||
./test_qrinput
|
||||
./test_qrspec
|
||||
./test_rs
|
||||
./test_split
|
||||
./test_mask
|
||||
./test_mqrspec
|
||||
./test_mmask
|
||||
./test_monkey
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 demerit;
|
||||
|
||||
frame = (unsigned char *)malloc(w * w);
|
||||
|
||||
testStart("Test mask evaluation (all white)");
|
||||
memset(frame, 0, w * w);
|
||||
demerit = Mask_evaluateSymbol(w, frame);
|
||||
testEndExp(demerit == ((N1 + 1)*w*2 + N2 * (w - 1) * (w - 1)));
|
||||
|
||||
testStart("Test mask evaluation (all black)");
|
||||
memset(frame, 1, w * w);
|
||||
demerit = Mask_evaluateSymbol(w, frame);
|
||||
testEndExp(demerit == ((N1 + 1)*w*2 + N2 * (w - 1) * (w - 1)));
|
||||
|
||||
free(frame);
|
||||
}
|
||||
|
||||
/* .#.#.#.#.#
|
||||
* #.#.#.#.#.
|
||||
* ..##..##..
|
||||
* ##..##..##
|
||||
* ...###...#
|
||||
* ###...###.
|
||||
* ....####..
|
||||
* ####....##
|
||||
* .....#####
|
||||
* #####.....
|
||||
*/
|
||||
static void test_eval2(void)
|
||||
{
|
||||
unsigned char *frame;
|
||||
unsigned int w = 10;
|
||||
int demerit;
|
||||
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;
|
||||
}
|
||||
demerit = Mask_evaluateSymbol(w, frame);
|
||||
testEndExp(demerit == N1 * 4 + N2 * 4);
|
||||
|
||||
free(frame);
|
||||
}
|
||||
|
||||
static void test_calcN2(void)
|
||||
{
|
||||
unsigned char frame[64];
|
||||
int width;
|
||||
int demerit;
|
||||
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;
|
||||
}
|
||||
}
|
||||
demerit = Mask_calcN2(width, frame);
|
||||
assert_equal(demerit, N2 * 4, "Calculation of N2 demerit is wrong: %d, expected %d", demerit, 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;
|
||||
}
|
||||
}
|
||||
demerit = Mask_calcN2(width, frame);
|
||||
assert_equal(demerit, N2 * 2, "Calculation of N2 demerit is wrong: %d, expected %d", demerit, N2 * 2);
|
||||
|
||||
width = 6;
|
||||
for(y = 0; y < width; y++) {
|
||||
for(x = 0; x < width; x++) {
|
||||
frame[y * width + x] = (x / 3) ^ (y / 3);
|
||||
}
|
||||
}
|
||||
demerit = Mask_calcN2(width, frame);
|
||||
assert_equal(demerit, N2 * 16, "Calculation of N2 demerit is wrong: %d, expected %d", demerit, N2 * 16);
|
||||
|
||||
testFinish();
|
||||
}
|
||||
|
||||
static void test_eval3(void)
|
||||
{
|
||||
unsigned char *frame;
|
||||
int w = 15;
|
||||
int demerit;
|
||||
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");
|
||||
}
|
||||
*/
|
||||
demerit = Mask_evaluateSymbol(w, frame);
|
||||
testEndExp(demerit == 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 demerit;
|
||||
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);
|
||||
demerit = Mask_calcN1N3(length, runLength);
|
||||
assert_equal(pattern[i][15], demerit, "N3 penalty is wrong: %d, expected %d\n", demerit, pattern[i][15]);
|
||||
}
|
||||
for(i=0; i<5; i++) {
|
||||
length = Mask_calcRunLengthH(18, pattern2[i], runLength);
|
||||
demerit = Mask_calcN1N3(length, runLength);
|
||||
assert_equal(pattern2[i][18], demerit, "N3 penalty is wrong: %d, expected %d\n", demerit, 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,347 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2012-10-14.11; # UTC
|
||||
|
||||
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,791 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2013-05-30.07; # UTC
|
||||
|
||||
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,527 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2011-11-20.07; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2013-10-28.13; # UTC
|
||||
|
||||
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=http://www.perl.org/
|
||||
flex_URL=http://flex.sourceforge.net/
|
||||
gnu_software_URL=http://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
|
@ -0,0 +1,148 @@
|
|||
#! /bin/sh
|
||||
# test-driver - basic testsuite driver script.
|
||||
|
||||
scriptversion=2013-07-13.22; # UTC
|
||||
|
||||
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
# Make unconditional expansion of undefined variables an error. This
|
||||
# helps a lot in preventing typo-related bugs.
|
||||
set -u
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$0: $*" >&2
|
||||
print_usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
cat <<END
|
||||
Usage:
|
||||
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
|
||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
||||
[--enable-hard-errors={yes|no}] [--]
|
||||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
|
||||
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
|
||||
END
|
||||
}
|
||||
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=no
|
||||
color_tests=no
|
||||
enable_hard_errors=yes
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "test-driver $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) enable_hard_errors=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
missing_opts=
|
||||
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
|
||||
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
|
||||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
|
||||
if test x"$missing_opts" != x; then
|
||||
usage_error "the following mandatory options are missing:$missing_opts"
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
usage_error "missing argument"
|
||||
fi
|
||||
|
||||
if test $color_tests = yes; then
|
||||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
|
||||
red='[0;31m' # Red.
|
||||
grn='[0;32m' # Green.
|
||||
lgn='[1;32m' # Light green.
|
||||
blu='[1;34m' # Blue.
|
||||
mgn='[0;35m' # Magenta.
|
||||
std='[m' # No color.
|
||||
else
|
||||
red= grn= lgn= blu= mgn= std=
|
||||
fi
|
||||
|
||||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
|
||||
trap "st=129; $do_exit" 1
|
||||
trap "st=130; $do_exit" 2
|
||||
trap "st=141; $do_exit" 13
|
||||
trap "st=143; $do_exit" 15
|
||||
|
||||
# Test script is run here.
|
||||
"$@" >$log_file 2>&1
|
||||
estatus=$?
|
||||
|
||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
||||
tweaked_estatus=1
|
||||
else
|
||||
tweaked_estatus=$estatus
|
||||
fi
|
||||
|
||||
case $tweaked_estatus:$expect_failure in
|
||||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
|
||||
0:*) col=$grn res=PASS recheck=no gcopy=no;;
|
||||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
|
||||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
|
||||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
|
||||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
|
||||
esac
|
||||
|
||||
# Report the test outcome and exit status in the logs, so that one can
|
||||
# know whether the test passed or failed simply by looking at the '.log'
|
||||
# file, without the need of also peaking into the corresponding '.trs'
|
||||
# file (automake bug#11814).
|
||||
echo "$res $test_name (exit status: $estatus)" >>$log_file
|
||||
|
||||
# Report outcome to console.
|
||||
echo "${col}${res}${std}: $test_name"
|
||||
|
||||
# Register the test result, and other relevant metadata.
|
||||
echo ":test-result: $res" > $trs_file
|
||||
echo ":global-test-result: $res" >> $trs_file
|
||||
echo ":recheck: $recheck" >> $trs_file
|
||||
echo ":copy-in-global-log: $gcopy" >> $trs_file
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
Loading…
Reference in New Issue