Page MenuHomePhabricator

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,63 +1,65 @@
+cmake_minimum_required(VERSION 2.6)
project(QuaZip)
-cmake_minimum_required(VERSION 2.6)
# CMP0042: Explicitly acknowledge MACOSX_RPATH
# (introduced in CMake 2.8.12, enabled by default in CMake 3.0,
# and producing a warning when unset since 3.7.1)
cmake_policy(SET CMP0042 NEW)
+set(QUAZIP_LIB_VERSION 0.9.1)
+set(QUAZIP_LIB_SOVERSION 1)
+
option(BUILD_WITH_QT4 "Build QuaZip with Qt4 no matter if Qt5 was found" OFF)
-if( NOT BUILD_WITH_QT4 )
+if(NOT BUILD_WITH_QT4)
# try Qt5 first, and prefer that if found
find_package(Qt5Core QUIET)
endif()
if(Qt5Core_FOUND)
set(CMAKE_CXX_STANDARD 11)
set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES})
set(QUAZIP_LIB_VERSION_SUFFIX 5)
# if there is no QT_ROOT, try to deduce it from Qt QtCore include
if("${QT_ROOT}" STREQUAL "")
set(QT_ROOT ${QT_QTCORE_INCLUDE_DIR}/../..)
endif()
include_directories(${Qt5Core_INCLUDE_DIRS})
macro(qt_wrap_cpp)
qt5_wrap_cpp(${ARGN})
endmacro()
else()
set(qt_min_version "4.5.0")
find_package(Qt4 REQUIRED)
set(QT_USE_QTGUI false)
include(${QT_USE_FILE})
include_directories(${QT_INCLUDES})
set(QTCORE_LIBRARIES ${QT_QTCORE_LIBRARY})
macro(qt_wrap_cpp)
qt4_wrap_cpp(${ARGN})
endmacro()
endif()
# Use system zlib on unix and Qt ZLIB on Windows
-if(UNIX OR MINGW)
- find_package(ZLIB REQUIRED)
-else(UNIX OR MINGW)
- set(ZLIB_INCLUDE_DIRS "${QT_ROOT}/src/3rdparty/zlib" CACHE STRING "Path to ZLIB headers of Qt")
- set(ZLIB_LIBRARIES "")
- if(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
- message("Please specify a valid zlib include dir")
- endif(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
-endif(UNIX OR MINGW)
+find_package(ZLIB REQUIRED)
# All build libraries are moved to this directory
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)")
set(LIB_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE STRING "Library directory name" FORCE)
+set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig" CACHE STRING "Installation directory for pkgconfig (.pc) files" FORCE)
set(QUAZIP_LIB_TARGET_NAME quazip${QUAZIP_LIB_VERSION_SUFFIX} CACHE
INTERNAL "Target name of libquazip" FORCE)
add_subdirectory(quazip)
-install(FILES FindQuaZip.cmake RENAME FindQuaZip${QUAZIP_LIB_VERSION_SUFFIX}.cmake DESTINATION ${CMAKE_ROOT}/Modules)
+if(UNIX AND NOT APPLE)
+ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/quazip.pc.cmakein
+ ${CMAKE_CURRENT_BINARY_DIR}/quazip.pc @ONLY)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/quazip.pc DESTINATION "${INSTALL_PKGCONFIG_DIR}")
+endif()
+
+install(FILES QuaZipConfig.cmake DESTINATION ${LIB_DESTINATION}/cmake/QuaZip${QUAZIP_LIB_VERSION_SUFFIX} RENAME QuaZip${QUAZIP_LIB_VERSION_SUFFIX}Config.cmake)
diff --git a/Doxyfile b/Doxyfile
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,1722 +1,1722 @@
# Doxyfile 1.7.4
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
# All text after a hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# http://www.gnu.org/software/libiconv for the list of possible encodings.
DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = QuaZIP
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = quazip-0-7-6
+PROJECT_NUMBER = quazip-0-9
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF =
# With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
PROJECT_LOGO =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = doc
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
# format and will distribute the generated files over these directories.
# Enabling this option can be useful when feeding doxygen a huge amount of
# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
CREATE_SUBDIRS = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator
# that is used to form the text in various listings. Each string
# in this list, if found as the leading text of the brief description, will be
# stripped from the text and the result after processing the whole list, is
# used as the annotated text. Otherwise, the brief description is used as-is.
# If left blank, the following values are used ("$name" is automatically
# replaced with the name of the entity): "The $name class" "The $name widget"
# "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the"
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
# description.
ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = YES
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
# the reader which header file to include in order to use a class.
# If left blank only the name of the header file containing the class
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful if your file system
# doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.)
JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
# interpret the first line (until the first dot) of a Qt-style
# comment as the brief description. If set to NO, the comments
# will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.)
QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
# comments) as a brief description. This used to be the default behaviour.
# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
# re-implements.
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
# a new page for each member. If set to NO, the documentation of a member will
# be part of the file/class/namespace that contains it.
SEPARATE_MEMBER_PAGES = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 8
# This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user-defined paragraph with heading "Side Effects:".
# You can put \n's in the value part of an alias to insert newlines.
ALIASES =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = NO
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
# sources only. Doxygen will then generate output that is more tailored for
# Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources only. Doxygen will then generate output that is more tailored for
# Fortran.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for
# VHDL.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this
# tag. The format is ext=language, where ext is a file extension, and language
# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
EXTENSION_MAPPING =
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
# func(std::string) {}). This also makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
BUILTIN_STL_SUPPORT = NO
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
# Doxygen will parse them like normal C++ but will assume all classes use public
# instead of private inheritance when no explicit protection keyword is present.
SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate getter
# and setter methods for a property. Setting this option to YES (the default)
# will make doxygen replace the get and set methods by a property in the
# documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
DISTRIBUTE_GROUP_DOC = NO
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
# the same type (for instance a group of public functions) to be put as a
# subgroup of that type (e.g. under the Public Functions section). Set it to
# NO to prevent subgrouping. Alternatively, this can be done per class using
# the \nosubgrouping command.
SUBGROUPING = YES
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
# unions are shown inside the group in which they are included (e.g. using
# @ingroup) instead of on a separate page (for HTML and Man pages) or
# section (for LaTeX and RTF).
INLINE_GROUPED_CLASSES = NO
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically
# be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
TYPEDEF_HIDES_STRUCT = NO
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
# determine which symbols to keep in memory and which to flush to disk.
# When the cache is full, less often used symbols will be written to disk.
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols
SYMBOL_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
EXTRACT_PRIVATE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
# the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default
# anonymous namespaces are hidden.
EXTRACT_ANON_NSPACES = NO
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations.
# If set to NO (the default) these declarations will be included in the
# documentation.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
# documentation blocks found inside the body of a function.
# If set to NO (the default) these blocks will be appended to the
# function's detailed documentation block.
HIDE_IN_BODY_DOCS = NO
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
# file names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put a list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = YES
# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
# will list include files with double quotes in the documentation
# rather than with sharp brackets.
FORCE_LOCAL_INCLUDES = NO
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = NO
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically
# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
# will sort the (brief and detailed) documentation of class members so that
# constructors and destructors are listed first. If set to NO (the default)
# the constructors will appear in the respective orders defined by
# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order.
SORT_GROUP_NAMES = NO
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
# sorted by fully-qualified names, including namespaces. If set to
# NO (the default), the class list will be sorted only by class name,
# not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the
# alphabetical list.
SORT_BY_SCOPE_NAME = NO
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
# do proper type resolution of all parameters of a function it will reject a
# match between the prototype and the implementation of a member function even
# if there is only one candidate or it is obvious which candidate to choose
# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
# will still accept a match between prototype and implementation in such cases.
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable (YES) or
# disable (NO) the bug list. This list is created by putting \bug
# commands in the documentation.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
# disable (NO) the deprecated list. This list is created by putting
# \deprecated commands in the documentation.
GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if sectionname ... \endif.
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or macro consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and macros in the
# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
SHOW_USED_FILES = YES
# If the sources in your project are distributed over multiple directories
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
SHOW_DIRECTORIES = YES
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page.
# This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command <command> <input-file>, where <command> is the value of
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
# provided by doxygen. Whatever the program writes to standard output
# is used as the file version. See the manual for examples.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. The create the layout file
# that represents doxygen's defaults, run doxygen with the -l option.
# You can optionally specify a file name after the option, if omitted
# DoxygenLayout.xml will be used as the name of the layout file.
LAYOUT_FILE =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
WARNINGS = YES
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some
# parameters in a documented function, or documenting parameters that
# don't exist or using markup commands wrongly.
WARN_IF_DOC_ERROR = YES
# The WARN_NO_PARAMDOC option can be enabled to get warnings for
# functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of
# documentation.
WARN_NO_PARAMDOC = NO
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
# warning originated and the warning text. Optionally the format may contain
# $version, which will be replaced by the version of the file (if it could
# be obtained via FILE_VERSION_FILTER)
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written
# to stderr.
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = quazip
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
# also the default input encoding. Doxygen uses libiconv (or the iconv built
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
# the list of possible encodings.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested:
# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
FILE_PATTERNS = *.cpp \
*.h \
*.dox
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = quazip/unzip.h \
quazip/zip.h \
quazip/ioapi.h \
quazip/minizip_crypt.h \
qztest/
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories. Note that the wildcards are matched
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
EXCLUDE_PATTERNS = */.moc/* */release/* */debug/* */moc_*.cpp
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
# the \include command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude
# commands irrespective of the value of the RECURSIVE tag.
# Possible values are YES and NO. If left blank NO is used.
EXAMPLE_RECURSIVE = NO
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
# the \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
# If FILTER_PATTERNS is specified, this tag will be
# ignored.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis.
# Doxygen will compare the file name with each pattern and apply the
# filter if there is a match.
# The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
# and it is also possible to disable source filtering for a specific pattern
# using *.ext= (so without naming a filter). This option only has effect when
# FILTER_SOURCE_FILES is enabled.
FILTER_SOURCE_PATTERNS =
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
# functions referencing it will be listed.
REFERENCED_BY_RELATION = YES
# If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities
# called/used by that function will be listed.
REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code.
# Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES
# If the USE_HTAGS tag is set to YES then the references to source code
# will point to the HTML generated by the htags(1) tool instead of doxygen
# built-in source browser. The htags tool is part of GNU's global source
# tagging system (see http://www.gnu.org/software/global/global.html). You
# will need version 4.8.6 or higher.
USE_HTAGS = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = NO
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension.
HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header. Note that when using a custom header you are responsible
# for the proper inclusion of any scripts and style sheets that doxygen
# needs, which is dependent on the configuration options used.
# It is adviced to generate a default header using "doxygen -w html
# header.html footer.html stylesheet.css YourConfigFile" and then modify
# that header. Note that the header is subject to change so you typically
# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
# will generate a default style sheet. Note that doxygen will try to copy
# the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased!
HTML_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that
# the files will be copied as-is; there are no commands or markers available.
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the stylesheet and background images
# according to this color. Hue is specified as an angle on a colorwheel,
# see http://en.wikipedia.org/wiki/Hue for more information.
# For instance the value 0 represents red, 60 is yellow, 120 is green,
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The allowed range is 0 to 359.
HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
# the colors in the HTML output. For a value of 0 the output will use
# grayscales only. A value of 255 will produce the most vivid colors.
HTML_COLORSTYLE_SAT = 100
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
# the luminance component of the colors in the HTML output. Values below
# 100 gradually make the output lighter, whereas values above 100 make
# the output darker. The value divided by 100 is the actual gamma applied,
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
# and 100 does not change the gamma.
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting
# this to NO can help when comparing the output of multiple runs.
HTML_TIMESTAMP = YES
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded. For this to work a browser that supports
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
HTML_DYNAMIC_SECTIONS = NO
# If the GENERATE_DOCSET tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3
# integrated development environment, introduced with OSX 10.5 (Leopard).
# To create a documentation set, doxygen will generate a Makefile in the
# HTML output directory. Running make will produce the docset in that
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
GENERATE_DOCSET = NO
# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
# feed. A documentation feed provides an umbrella under which multiple
# documentation sets from a single provider (such as a company or product suite)
# can be grouped.
DOCSET_FEEDNAME = "Doxygen generated docs"
# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
# should uniquely identify the documentation set bundle. This should be a
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
# will append .docset to the name.
DOCSET_BUNDLE_ID = org.doxygen.Project
# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
# be used to specify the file name of the resulting .chm file. You
# can add a path in front of the file if the result should not be
# written to the html output directory.
CHM_FILE =
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
# be used to specify the location (absolute path including file name) of
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
# the HTML help compiler on the generated index.hhp.
HHC_LOCATION =
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
# controls if a separate .chi index file is generated (YES) or that
# it should be included in the master .chm file (NO).
GENERATE_CHI = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
# content.
CHM_INDEX_ENCODING =
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
# controls whether a binary table of contents is generated (YES) or a
# normal table of contents (NO) in the .chm file.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members
# to the contents of the HTML help documentation and to the tree view.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
# that can be used as input for Qt's qhelpgenerator to generate a
# Qt Compressed Help (.qch) of the generated HTML documentation.
GENERATE_QHP = NO
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
# be used to specify the file name of the resulting .qch file.
# The path specified is relative to the HTML output folder.
QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
QHP_VIRTUAL_FOLDER = doc
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
# Qt Help Project / Custom Filters</a>.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
# Qt Help Project / Filter Attributes</a>.
QHP_SECT_FILTER_ATTRS =
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
QHG_LOCATION =
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
# will be generated, which together with the HTML files, form an Eclipse help
# plugin. To install this plugin and make it available under the help contents
# menu in Eclipse, the contents of the directory containing the HTML and XML
# files needs to be copied into the plugins directory of eclipse. The name of
# the directory within the plugins directory should be the same as
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
# the help appears.
GENERATE_ECLIPSEHELP = NO
# A unique identifier for the eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have
# this name.
ECLIPSE_DOC_ID = org.doxygen.Project
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
DISABLE_INDEX = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
# (range [0,1..20]) that doxygen will group on one line in the generated HTML
# documentation. Note that a value of 0 will completely suppress the enum
# values from appearing in the overview section.
ENUM_VALUES_PER_LINE = 4
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
# If the tag value is set to YES, a side panel will be generated
# containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
# Windows users are probably better off using the HTML help feature.
GENERATE_TREEVIEW = NO
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list.
USE_INLINE_TREES = NO
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
TREEVIEW_WIDTH = 250
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
# links to external symbols imported via tag files in a separate window.
EXT_LINKS_IN_WINDOW = NO
# Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need
# to manually remove any form_*.png images from the HTML output directory
# to force them to be regenerated.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are
# not supported properly for IE 6.0, but are supported on all modern browsers.
# Note that when changing this option you need to delete any form_*.png files
# in the HTML output before the changes have effect.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
# (see http://www.mathjax.org) which uses client side Javascript for the
# rendering instead of using prerendered bitmaps. Use this if you do not
# have LaTeX installed or if you want to formulas look prettier in the HTML
# output. When enabled you also need to install MathJax separately and
# configure the path to it using the MATHJAX_RELPATH option.
USE_MATHJAX = NO
# When MathJax is enabled you need to specify the location relative to the
# HTML output directory using the MATHJAX_RELPATH option. The destination
# directory should contain the MathJax.js script. For instance, if the mathjax
# directory is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to the
# mathjax.org site, so you can quickly see the result without installing
# MathJax, but it is strongly recommended to install a local copy of MathJax
# before deployment.
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
# (GENERATE_DOCSET) there is already a search function so this one should
# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a PHP enabled web server instead of at the web client
# using Javascript. Doxygen will generate the search PHP script and index
# file to put on the web server. The advantage of the server
# based approach is that it scales better to large projects and allows
# full text search. The disadvantages are that it is more difficult to setup
# and does not have live searching capabilities.
SERVER_BASED_SEARCH = NO
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
# Note that when enabling USE_PDFLATEX this option is only used for
# generating bitmaps for formulas in the HTML output, but not in the
# Makefile that is written to the output directory.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
# the generated latex document. The footer should contain everything after
# the last chapter. If it is left blank doxygen will generate a
# standard footer. Notice: only use this tag if you know what you are doing!
LATEX_FOOTER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = NO
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
LATEX_HIDE_INDICES = NO
# If LATEX_SOURCE_CODE is set to YES then doxygen will include
# source code with syntax highlighting in the LaTeX output.
# Note that which sources are shown also depends on other settings
# such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimized for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an rtf document.
# Syntax is similar to doxygen's config file.
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
# then it will generate one additional man file for each entity
# documented in the real man page(s). These additional files
# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `xml' will be used as the default path.
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify an XML schema,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_SCHEMA =
# The XML_DTD tag can be used to specify an XML DTD,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
# generate an AutoGen Definitions (see autogen.sf.net) file
# that captures the structure of the code including all
# documentation. Note that this feature is still experimental
# and incomplete at the moment.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
# generate a Perl module file that captures the structure of
# the code including all documentation. Note that this
# feature is still experimental and incomplete at the
# moment.
GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
# to generate PDF and DVI output from the Perl module output.
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader.
# This is useful
# if you want to understand what is going on.
# On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
PERLMOD_PRETTY = YES
# The names of the make variables in the generated doxyrules.make file
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
# This is useful so different doxyrules.make files included by the same
# Makefile don't overwrite each other's variables.
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# pointed to by INCLUDE_PATH will be searched when a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition that
# overrules the definition found in the source code.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all references to function-like macros
# that are alone on a line, have an all uppercase name, and do not end with a
# semicolon, because these will confuse the parser if not removed.
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
# The TAGFILES option can be used to specify one or more tagfiles.
# Optionally an initial location of the external documentation
# can be added for each tagfile. The format of a tag file without
# this location is as follows:
#
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
#
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths or
# URLs. If a location is present for each tag, the installdox tool
# does not have to be run to correct the links.
# Note that each tag file must have a unique name
# (where the name does NOT include the path)
# If a tag file is not located in the directory in which doxygen
# is run, you must also specify the path to the tagfile here.
TAGFILES = qtcore.tags=http://doc.qt.io/qt-5.9/
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
# will be listed.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will
# be listed.
EXTERNAL_GROUPS = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that
# this option also works with HAVE_DOT disabled, but it is recommended to
# install and use dot, since it yields more powerful graphs.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
# or is not a class.
HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will
# base this on the number of processors available in the system. You can set it
# explicitly to a value larger than 0 to get control over the balance
# between CPU load and processing speed.
DOT_NUM_THREADS = 0
# By default doxygen will write a font called Helvetica to the output
# directory and reference it in all dot files that doxygen generates.
# When you want a differently looking font you can specify the font name
# using DOT_FONTNAME. You need to make sure dot is able to find the font,
# which can be done by putting it in a standard location or by setting the
# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
# containing the font.
DOT_FONTNAME = Helvetica
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the output directory to look for the
# FreeSans.ttf font (which doxygen will put there itself). If you specify a
# different font using DOT_FONTNAME you can set the path where dot
# can find it using this tag.
DOT_FONTPATH =
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
UML_LOOK = NO
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
TEMPLATE_RELATIONS = NO
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
# tags are set to YES then doxygen will generate a graph for each documented
# file showing the direct and indirect include dependencies of the file with
# other documented files.
INCLUDE_GRAPH = YES
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
# documented header file showing the documented files that directly or
# indirectly include this file.
INCLUDED_BY_GRAPH = YES
# If the CALL_GRAPH and HAVE_DOT options are set to YES then
# doxygen will generate a call dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
CALL_GRAPH = NO
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will generate a graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are svg, png, jpg, or gif.
# If left blank png will be used.
DOT_IMAGE_FORMAT = png
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the
# \dotfile command).
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the
# \mscfile command).
MSCFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is
# visualized by representing a node as a red box. Note that doxygen if the
# number of direct children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
DOT_GRAPH_MAX_NODES = 50
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
# graphs generated by dot. A depth value of 3 means that only nodes reachable
# from the root by following a path via at most 3 edges will be shown. Nodes
# that lay further from the root node will be omitted. Note that setting this
# option to 1 or 2 may greatly reduce the computation time needed for large
# code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not
# seem to support this out of the box. Warning: Depending on the platform used,
# enabling this option may lead to badly anti-aliased labels on the edges of
# a graph (i.e. they become hard to read).
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10)
# support this, this feature is disabled by default.
DOT_MULTI_TARGETS = NO
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and
# arrows in the dot generated graphs.
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
# remove the intermediate dot files that are used to generate
# the various graphs.
DOT_CLEANUP = YES
diff --git a/FindQuaZip.cmake b/FindQuaZip.cmake
deleted file mode 100644
--- a/FindQuaZip.cmake
+++ /dev/null
@@ -1,43 +0,0 @@
-# QUAZIP_FOUND - QuaZip library was found
-# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir
-# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR)
-# QUAZIP_LIBRARIES - List of QuaZip libraries
-# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers
-
-
-IF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES)
- # in cache already
- SET(QUAZIP_FOUND TRUE)
-ELSE (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES)
- IF (Qt5Core_FOUND)
- set(QUAZIP_LIB_VERSION_SUFFIX 5)
- ENDIF()
- IF (WIN32)
- FIND_PATH(QUAZIP_LIBRARY_DIR
- WIN32_DEBUG_POSTFIX d
- NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll
- HINTS "C:/Programme/" "C:/Program Files"
- PATH_SUFFIXES QuaZip/lib
- )
- FIND_LIBRARY(QUAZIP_LIBRARIES NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll HINTS ${QUAZIP_LIBRARY_DIR})
- FIND_PATH(QUAZIP_INCLUDE_DIR NAMES quazip.h HINTS ${QUAZIP_LIBRARY_DIR}/../ PATH_SUFFIXES include/quazip)
- FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR NAMES zlib.h)
- ELSE(WIN32)
- FIND_PACKAGE(PkgConfig)
-# pkg_check_modules(PC_QCA2 QUIET qca2)
- pkg_check_modules(PC_QUAZIP quazip)
- FIND_LIBRARY(QUAZIP_LIBRARIES
- WIN32_DEBUG_POSTFIX d
- NAMES quazip${QUAZIP_LIB_VERSION_SUFFIX}
- HINTS /usr/lib /usr/lib64
- )
- FIND_PATH(QUAZIP_INCLUDE_DIR quazip.h
- HINTS /usr/include /usr/local/include
- PATH_SUFFIXES quazip${QUAZIP_LIB_VERSION_SUFFIX}
- )
- FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR zlib.h HINTS /usr/include /usr/local/include)
- ENDIF (WIN32)
- INCLUDE(FindPackageHandleStandardArgs)
- SET(QUAZIP_INCLUDE_DIRS ${QUAZIP_INCLUDE_DIR} ${QUAZIP_ZLIB_INCLUDE_DIR})
- find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_LIBRARIES QUAZIP_INCLUDE_DIR QUAZIP_ZLIB_INCLUDE_DIR QUAZIP_INCLUDE_DIRS)
-ENDIF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES)
diff --git a/NEWS.txt b/NEWS.txt
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,178 +1,190 @@
QuaZIP changes
+* 2020-04-29 0.9
+ * Support for extended timestamps
+ * Various contributed CMake fixes
+
+* 2019-05-27 0.8.1
+ * CMake regression fix
+
+* 2019-05-23 0.8
+ * Support for UTF-8 in file names and comments (Denis Zavorotnyy)
+ * get/setOsCode(), get/setDefaultOsCode()
+ * Fixed Z_STREAM_END handling in QuaZioDevice
+
* 2018-06-13 0.7.6
* Fixed the Zip Slip vulnerability in JlCompress
* Renamed crypt.h to minizip_crypt.h to avoid conflicts
* 2018-05-20 0.7.5
* Fixed target_link_libraries call in CMakeLists
* Worked around a Qt 4.6 bug (QTBUG-15421) screwing up hidden
files handling in JlCompress::compressDir()
* Removed Q_FOREACH uses to avoid conflicts (SF patch #32)
* 2017-02-05 0.7.4
* Static analysis patch from Intel Deutschland GmbH
* Replaced UNUSED with QUAZIP_UNUSED to avoid name clashes
* Minor bug fixes
* 2017-02-05 0.7.3
* Symlink handling
* Static linking exception for LGPL
* Minor bug fixes
* 2016-03-29 0.7.2
* New JlCompress methods (QIODevice*-based API by Lukasz Kwiecinski)
* Implemented QuaZioDevice::atEnd() and bytesAvailable()--these might
break ABI, but pretty unlikely.
* 2015-01-07 0.7.1
* Fixed licensing issues (bug #45).
* Added the convenience method QuaZipFileInfo::isEncrypted().
* 2014-07-24 0.7
* It is now possible to write ZIP files to sequential devices
like sockets (only in mdCreate mode, so no self-extract, sorry).
* A few zip64 fixes.
* Several bug fixes and portability improvements.
* 2014-02-09 0.6.2
* QuaZipNewInfo / QuaZipFileInfo64 now provide API to access/set
NTFS time stamps - useful even on non-NTFS systems if you
need more precise dates and times than default ones.
* QuaZipNewInfo may now be initialized from QuaZipFileInfo64.
* No more crashes when using QSaveFile as QIODevice for ZIP.
* The new QuaZip::setAutoClose() method allows to leave the
QIODevice open when you close the QuaZip instance.
* qztest now depends on quazip, no longer breaking the build.
* 2014-01-26 0.6.1
* Improved zip64 support.
* A LOT more tests thanks to g++ --coverage / lcov.
* JlCompress extraction methods now create files with default
permissions if they are zero in the original archive.
* Some QuaZipDir fixes (thanks to the new tests).
* 2014-01-22 0.6
* Minizip updated to 1.1 (with all the necessary modifications
re-done), and that means that...
* the long-awaited zip64 support is now available!
* A few rather minor fixes.
* 2014-01-19 0.5.2
* Some minor bug fixes.
* API to access file permissions subfield of the external
attributes.
* MS VS 2012 Express support.
* API to set the default codec used to encode/decode file names
(mainly for use by various wrappers such as JlCompress, when
you don't have direct access to the underlying QuaZip instance).
* 2013-03-02 0.5.1
* Lots of QuaZipDir fixes, thanks to all bug reporters.
* Full Qt Creator support.
* MS VS 2010 Express support.
* Qt5 support (didn't need any source code changes anyway).
* Lots of minor bug fixes.
* 2012-09-07 0.5
* Added run_moc.bat files for building under Windows in case Qt
integration is not available (e. g. VS 2008 Express).
* Added the QuaZipDir class to simplify ZIP navigation in terms
of directories.
* Added the QuaGzipFile class for working with GZIP archives. It
was added as a bonus since it has nothing to do with the main
purpose of the library. It probably won't get any major
improvements, although minor bug fixes are possible.
* Added the QuaZIODevice class for working with zlib
compression. It has nothing to do with the ZIP format, and
therefore the same notice as for the QuaGzipFile applies.
* The global comment is no longer erased when adding files to
an archive.
* Many bug fixes.
* 2012-01-14 0.4.4
* Fixed isSequential() test that was causing open() failures on
Unix.
* Fixed sub-directory compressing in JlCompress.
* Added MS VS 2008 solution, compatible with the binary Qt
distribution (tested on MS VS 2008 Express, had to run MOC
manually due to the lack of plugin in Express).
* Fixed extracting directories in JlCompress.
* Fixed JlCompress.h includes in the test suite, which used
lowercase names thus breaking on case-sensitive systems.
* Implemented missing QuaZipFile::getZip() that was only
declared.
* Fixed reopening closed files.
* Fixed possible memory leak in case of open error.
* 2011-09-09 0.4.3
* New test suite using QTestLib.
* Fixed bytesAvailable(), pos() and atEnd().
* Added ZIP v1.0 support and disabling data descriptor for
compatibility with some older software.
* Fixed DLL export/import issues for some symbols.
* Added QUAZIP_STATIC macro for compiling as a static library or
directly including the source.
* Added getFileNameList() and getFileInfoList() convenience
functions.
* Added some buffering to JlCompress to improve performance.
* 2011-08-10 0.4.2
* Cmake patch (thanks to Bernhard Rosenkraenzer).
* Symbian patch (thanks to Hamish Willee).
* Documented the multiple files limitation of QuaZipFile.
* Fixed relative paths handling in JlCompress.
* Fixed linking to MinGW zlib.
* 2011-05-26 0.4.1
* License statement updated to avoid confusion. GPL license
removed for the very same reason.
* Parts of original package are now clearly marked as modified,
just as their license requires.
* 2011-05-23 0.4
* QuaZip and QuaZipFile classes now use the Pimpl idiom. This
means that future releases will probably be binary compatible
with this one, but it also means that this one is binary
incompatible with the old ones.
* IO API has been rewritten using QIODevice instead of standard
C library. Among other things it means that QuaZip now supports
files up to 4 GB in size instead of 2 GB.
* Added QuaZip methods allowing access to ZIP files represented
by any seekable QIODevice implementation (QBuffer is a good
example).
* 2010-07-23 0.3
* Fixed getComment() for global comments.
* Added some useful classes for calculating checksums (thanks to
Adam Walczak).
* Added some utility classes for working with whole directories
(thanks to Roberto Pompermaier). It would be nice if someone
documents these in English, though.
* Probably fixed some problems with passwords (thanks to Vasiliy
Sorokin). I didn't test it, though.
* 2008-09-17 0.2.3
* Fixed license notices in sources.
* SVN
* Fixed a small bug in QuaZipFile::atEnd().
* 2007-01-16 0.2.2
* Added LGPL as alternative license.
* Added FAQ documentation page.
* 2006-03-21 0.2.1
* Fixed setCommentCodec() bug.
* Fixed bug that set month 1-12 instead of 0-11, as specified in
zip.h.
* Added workaround for Qt's bug that caused wrong timestamps.
* Few documentation fixes and cosmetic changes.
* 2005-07-08 0.2
* Write support.
* Extended QuaZipFile API, including size(), *pos() functions.
* Support for comments encoding/decoding.
* 2005-07-01 0.1
* Initial version.
diff --git a/QuaZipConfig.cmake b/QuaZipConfig.cmake
new file mode 100644
--- /dev/null
+++ b/QuaZipConfig.cmake
@@ -0,0 +1,43 @@
+# QUAZIP_FOUND - QuaZip library was found
+# QUAZIP_INCLUDE_DIR - Path to QuaZip include dir
+# QUAZIP_INCLUDE_DIRS - Path to QuaZip and zlib include dir (combined from QUAZIP_INCLUDE_DIR + ZLIB_INCLUDE_DIR)
+# QUAZIP_LIBRARIES - List of QuaZip libraries
+# QUAZIP_ZLIB_INCLUDE_DIR - The include dir of zlib headers
+
+
+IF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES)
+ # in cache already
+ SET(QUAZIP_FOUND TRUE)
+ELSE (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES)
+ IF (Qt5Core_FOUND)
+ set(QUAZIP_LIB_VERSION_SUFFIX 5)
+ ENDIF()
+ IF (WIN32)
+ FIND_PATH(QUAZIP_LIBRARY_DIR
+ WIN32_DEBUG_POSTFIX d
+ NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll
+ HINTS "C:/Programme/" "C:/Program Files"
+ PATH_SUFFIXES QuaZip/lib
+ )
+ FIND_LIBRARY(QUAZIP_LIBRARIES NAMES libquazip${QUAZIP_LIB_VERSION_SUFFIX}.dll HINTS ${QUAZIP_LIBRARY_DIR})
+ FIND_PATH(QUAZIP_INCLUDE_DIR NAMES quazip.h HINTS ${QUAZIP_LIBRARY_DIR}/../ PATH_SUFFIXES include/quazip${QUAZIP_LIB_VERSION_SUFFIX})
+ FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR NAMES zlib.h)
+ ELSE(WIN32)
+ FIND_PACKAGE(PkgConfig)
+# pkg_check_modules(PC_QCA2 QUIET qca2)
+ pkg_check_modules(PC_QUAZIP quazip)
+ FIND_LIBRARY(QUAZIP_LIBRARIES
+ WIN32_DEBUG_POSTFIX d
+ NAMES quazip${QUAZIP_LIB_VERSION_SUFFIX}
+ HINTS /usr/lib /usr/lib64
+ )
+ FIND_PATH(QUAZIP_INCLUDE_DIR quazip.h
+ HINTS /usr/include /usr/local/include
+ PATH_SUFFIXES quazip${QUAZIP_LIB_VERSION_SUFFIX}
+ )
+ FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR zlib.h HINTS /usr/include /usr/local/include)
+ ENDIF (WIN32)
+ INCLUDE(FindPackageHandleStandardArgs)
+ SET(QUAZIP_INCLUDE_DIRS ${QUAZIP_INCLUDE_DIR} ${QUAZIP_ZLIB_INCLUDE_DIR})
+ find_package_handle_standard_args(QUAZIP DEFAULT_MSG QUAZIP_LIBRARIES QUAZIP_INCLUDE_DIR QUAZIP_ZLIB_INCLUDE_DIR QUAZIP_INCLUDE_DIRS)
+ENDIF (QUAZIP_INCLUDE_DIRS AND QUAZIP_LIBRARIES)
diff --git a/project.diff b/project.diff
--- a/project.diff
+++ b/project.diff
@@ -1,60 +1,60 @@
diff -u a/quazip/quazip.pri b/quazip/quazip.pri
--- a/quazip/quazip.pri 2023-05-31 17:48:37.368339456 +0300
+++ b/quazip/quazip.pri 2021-11-26 15:47:56.789035840 +0300
@@ -3,13 +3,7 @@
HEADERS += \
$$PWD/minizip_crypt.h \
$$PWD/ioapi.h \
- $$PWD/JlCompress.h \
- $$PWD/quaadler32.h \
- $$PWD/quachecksum32.h \
- $$PWD/quacrc32.h \
- $$PWD/quagzipfile.h \
$$PWD/quaziodevice.h \
- $$PWD/quazipdir.h \
$$PWD/quazipfile.h \
$$PWD/quazipfileinfo.h \
$$PWD/quazip_global.h \
@@ -19,13 +13,8 @@
$$PWD/zip.h
SOURCES += $$PWD/qioapi.cpp \
- $$PWD/JlCompress.cpp \
- $$PWD/quaadler32.cpp \
- $$PWD/quacrc32.cpp \
- $$PWD/quagzipfile.cpp \
$$PWD/quaziodevice.cpp \
$$PWD/quazip.cpp \
- $$PWD/quazipdir.cpp \
$$PWD/quazipfile.cpp \
$$PWD/quazipfileinfo.cpp \
$$PWD/quazipnewinfo.cpp \
diff -u a/qztest/qztest.pro b/qztest/qztest.pro
--- a/qztest/qztest.pro 2023-05-31 17:48:37.376339390 +0300
+++ b/qztest/qztest.pro 2019-09-12 15:40:14.057107000 +0300
-@@ -16,23 +16,19 @@
+@@ -21,23 +21,19 @@
# Input
HEADERS += qztest.h \
+JlCompress.h \
testjlcompress.h \
-testquachecksum32.h \
-testquagzipfile.h \
testquaziodevice.h \
-testquazipdir.h \
testquazipfile.h \
testquazip.h \
testquazipnewinfo.h \
testquazipfileinfo.h
SOURCES += qztest.cpp \
+JlCompress.cpp \
testjlcompress.cpp \
-testquachecksum32.cpp \
-testquagzipfile.cpp \
testquaziodevice.cpp \
testquazip.cpp \
-testquazipdir.cpp \
testquazipfile.cpp \
testquazipnewinfo.cpp \
testquazipfileinfo.cpp
diff --git a/quazip.pc.cmakein b/quazip.pc.cmakein
new file mode 100644
--- /dev/null
+++ b/quazip.pc.cmakein
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${prefix}/lib@LIB_SUFFIX@
+includedir=${prefix}/include
+
+
+Name: Quazip
+Description: Quazip Library
+Version: @QUAZIP_LIB_VERSION@
+Libs: -lquazip@QUAZIP_LIB_VERSION_SUFFIX@
+Cflags:
+Requires: Qt5Core
diff --git a/quazip/CMakeLists.txt b/quazip/CMakeLists.txt
--- a/quazip/CMakeLists.txt
+++ b/quazip/CMakeLists.txt
@@ -1,32 +1,31 @@
-# set all include directories for in and out of source builds
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_BINARY_DIR}
- ${ZLIB_INCLUDE_DIRS}
-)
-
file(GLOB SRCS "*.c" "*.cpp")
file(GLOB PUBLIC_HEADERS "*.h")
+set(QUAZIP_LIB_VERSION 1.0.0)
+set(QUAZIP_LIB_SOVERSION 1)
+
# Must be added to enable export macro
ADD_DEFINITIONS(-DQUAZIP_BUILD)
qt_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS})
set(SRCS ${SRCS} ${MOC_SRCS})
add_library(${QUAZIP_LIB_TARGET_NAME} SHARED ${SRCS})
add_library(quazip_static STATIC ${SRCS})
# Windows uses .lib extension for both static and shared library
# *nix systems use different extensions for SHARED and STATIC library and by convention both libraries have the same name
if (NOT WIN32)
set_target_properties(quazip_static PROPERTIES OUTPUT_NAME quazip${QUAZIP_LIB_VERSION_SUFFIX})
endif ()
-set_target_properties(${QUAZIP_LIB_TARGET_NAME} quazip_static PROPERTIES VERSION 1.0.0 SOVERSION 1 DEBUG_POSTFIX d)
+target_include_directories(${QUAZIP_LIB_TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${ZLIB_INCLUDE_DIRS})
+target_include_directories(quazip_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${ZLIB_INCLUDE_DIRS})
+set_target_properties(${QUAZIP_LIB_TARGET_NAME} quazip_static PROPERTIES VERSION ${QUAZIP_LIB_VERSION} SOVERSION ${QUAZIP_LIB_SOVERSION} DEBUG_POSTFIX d)
+
# Link against ZLIB_LIBRARIES if needed (on Windows this variable is empty)
target_link_libraries(${QUAZIP_LIB_TARGET_NAME} ${QT_QTMAIN_LIBRARY} ${QTCORE_LIBRARIES} ${ZLIB_LIBRARIES})
target_link_libraries(quazip_static ${QT_QTMAIN_LIBRARY} ${QTCORE_LIBRARIES} ${ZLIB_LIBRARIES})
install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip${QUAZIP_LIB_VERSION_SUFFIX})
install(TARGETS ${QUAZIP_LIB_TARGET_NAME} quazip_static LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION})
diff --git a/quazip/ioapi.h b/quazip/ioapi.h
--- a/quazip/ioapi.h
+++ b/quazip/ioapi.h
@@ -1,207 +1,207 @@
/* ioapi.h -- IO base function header for compress/uncompress .zip
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
Modified by Sergey A. Tachenov to allow QIODevice API usage.
For more info read MiniZip_info.txt
Changes
Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
More if/def section may be needed to support other platforms
Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
(but you should use iowin32.c for windows instead)
*/
#ifndef _ZLIBIOAPI64_H
#define _ZLIBIOAPI64_H
#if (!defined(_WIN32)) && (!defined(WIN32))
// Linux needs this to support file operation on files larger then 4+GB
// But might need better if/def to select just the platforms that needs them.
#ifndef __USE_FILE_OFFSET64
#define __USE_FILE_OFFSET64
#endif
#ifndef __USE_LARGEFILE64
#define __USE_LARGEFILE64
#endif
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
-#include "zlib.h"
+#include <zlib.h>
#if defined(USE_FILE32API)
#define fopen64 fopen
#define ftello64 ftell
#define fseeko64 fseek
#else
#ifdef _MSC_VER
#define fopen64 fopen
#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
#define ftello64 _ftelli64
#define fseeko64 _fseeki64
#else // old MSC
#define ftello64 ftell
#define fseeko64 fseek
#endif
#endif
#endif
/*
#ifndef ZPOS64_T
#ifdef _WIN32
#define ZPOS64_T fpos_t
#else
#include <stdint.h>
#define ZPOS64_T uint64_t
#endif
#endif
*/
#ifdef HAVE_MINIZIP64_CONF_H
#include "mz64conf.h"
#endif
/* a type choosen by DEFINE */
#ifdef HAVE_64BIT_INT_CUSTOM
typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
#else
#ifdef HAS_STDINT_H
#include "stdint.h"
typedef uint64_t ZPOS64_T;
#else
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 ZPOS64_T;
#else
typedef unsigned long long int ZPOS64_T;
#endif
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef OF
#define OF _Z_OF
#endif
#define ZLIB_FILEFUNC_SEEK_CUR (1)
#define ZLIB_FILEFUNC_SEEK_END (2)
#define ZLIB_FILEFUNC_SEEK_SET (0)
#define ZLIB_FILEFUNC_MODE_READ (1)
#define ZLIB_FILEFUNC_MODE_WRITE (2)
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
#define ZLIB_FILEFUNC_MODE_CREATE (8)
#ifndef ZCALLBACK
#if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
#define ZCALLBACK CALLBACK
#else
#define ZCALLBACK
#endif
#endif
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode));
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
typedef uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
/* here is the "old" 32 bits structure structure */
typedef struct zlib_filefunc_def_s
{
open_file_func zopen_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell_file_func ztell_file;
seek_file_func zseek_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc_def;
typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
typedef int (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, voidpf file, int mode));
typedef struct zlib_filefunc64_def_s
{
open64_file_func zopen64_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell64_file_func ztell64_file;
seek64_file_func zseek64_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
close_file_func zfakeclose_file; // for no-auto-close flag
} zlib_filefunc64_def;
void fill_qiodevice64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
/* now internal definition, only for zip.c and unzip.h */
typedef struct zlib_filefunc64_32_def_s
{
zlib_filefunc64_def zfile_func64;
open_file_func zopen32_file;
tell_file_func ztell32_file;
seek_file_func zseek32_file;
} zlib_filefunc64_32_def;
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
#define ZFAKECLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zfakeclose_file)) ((filefunc).zfile_func64.opaque,filestream))
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode));
int call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
#ifdef __cplusplus
}
#endif
#endif
diff --git a/quazip/qioapi.cpp b/quazip/qioapi.cpp
--- a/quazip/qioapi.cpp
+++ b/quazip/qioapi.cpp
@@ -1,363 +1,363 @@
/* ioapi.c -- IO base function header for compress/uncompress .zip
files using zlib + zip or unzip API
Version 1.01e, February 12th, 2005
Copyright (C) 1998-2005 Gilles Vollant
Modified by Sergey A. Tachenov to integrate with Qt.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <zlib.h>
-#include "zlib.h"
#include "ioapi.h"
#include "quazip_global.h"
-#include <QIODevice>
+#include <QtCore/QIODevice>
#if (QT_VERSION >= 0x050100)
#define QUAZIP_QSAVEFILE_BUG_WORKAROUND
#endif
#ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND
-#include <QSaveFile>
+#include <QtCore/QSaveFile>
#endif
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,voidpf file,int mode)
{
if (pfilefunc->zfile_func64.zopen64_file != NULL)
return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,file,mode);
else
{
return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,file,mode);
}
}
int call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
{
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
else
{
uLong offsetTruncated = (uLong)offset;
if (offsetTruncated != offset)
return -1;
else
return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
}
}
ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
{
if (pfilefunc->zfile_func64.zseek64_file != NULL)
return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
else
{
uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
if ((tell_uLong) == ((uLong)-1))
return (ZPOS64_T)-1;
else
return tell_uLong;
}
}
/// @cond internal
struct QIODevice_descriptor {
// Position only used for writing to sequential devices.
qint64 pos;
inline QIODevice_descriptor():
pos(0)
{}
};
/// @endcond
voidpf ZCALLBACK qiodevice_open_file_func (
voidpf opaque,
voidpf file,
int mode)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
QIODevice *iodevice = reinterpret_cast<QIODevice*>(file);
QIODevice::OpenMode desiredMode;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
desiredMode = QIODevice::ReadOnly;
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
desiredMode = QIODevice::ReadWrite;
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
desiredMode = QIODevice::WriteOnly;
if (iodevice->isOpen()) {
if ((iodevice->openMode() & desiredMode) == desiredMode) {
if (desiredMode != QIODevice::WriteOnly
&& iodevice->isSequential()) {
// We can use sequential devices only for writing.
delete d;
return NULL;
} else {
if ((desiredMode & QIODevice::WriteOnly) != 0) {
// open for writing, need to seek existing device
if (!iodevice->isSequential()) {
iodevice->seek(0);
} else {
d->pos = iodevice->pos();
}
}
}
return iodevice;
} else {
delete d;
return NULL;
}
}
iodevice->open(desiredMode);
if (iodevice->isOpen()) {
if (desiredMode != QIODevice::WriteOnly && iodevice->isSequential()) {
// We can use sequential devices only for writing.
iodevice->close();
delete d;
return NULL;
} else {
return iodevice;
}
} else {
delete d;
return NULL;
}
}
uLong ZCALLBACK qiodevice_read_file_func (
voidpf opaque,
voidpf stream,
void* buf,
uLong size)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream);
qint64 ret64 = iodevice->read((char*)buf,size);
uLong ret;
ret = (uLong) ret64;
if (ret64 != -1) {
d->pos += ret64;
}
return ret;
}
uLong ZCALLBACK qiodevice_write_file_func (
voidpf opaque,
voidpf stream,
const void* buf,
uLong size)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream);
uLong ret;
qint64 ret64 = iodevice->write((char*)buf,size);
if (ret64 != -1) {
d->pos += ret64;
}
ret = (uLong) ret64;
return ret;
}
uLong ZCALLBACK qiodevice_tell_file_func (
voidpf opaque,
voidpf stream)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream);
uLong ret;
qint64 ret64;
if (iodevice->isSequential()) {
ret64 = d->pos;
} else {
ret64 = iodevice->pos();
}
ret = static_cast<uLong>(ret64);
return ret;
}
ZPOS64_T ZCALLBACK qiodevice64_tell_file_func (
voidpf opaque,
voidpf stream)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream);
qint64 ret;
if (iodevice->isSequential()) {
ret = d->pos;
} else {
ret = iodevice->pos();
}
return static_cast<ZPOS64_T>(ret);
}
int ZCALLBACK qiodevice_seek_file_func (
voidpf /*opaque UNUSED*/,
voidpf stream,
uLong offset,
int origin)
{
QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream);
if (iodevice->isSequential()) {
if (origin == ZLIB_FILEFUNC_SEEK_END
&& offset == 0) {
// sequential devices are always at end (needed in mdAppend)
return 0;
} else {
qWarning("qiodevice_seek_file_func() called for sequential device");
return -1;
}
}
uLong qiodevice_seek_result=0;
int ret;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset;
break;
case ZLIB_FILEFUNC_SEEK_END :
qiodevice_seek_result = ((QIODevice*)stream)->size() - offset;
break;
case ZLIB_FILEFUNC_SEEK_SET :
qiodevice_seek_result = offset;
break;
default:
return -1;
}
ret = !iodevice->seek(qiodevice_seek_result);
return ret;
}
int ZCALLBACK qiodevice64_seek_file_func (
voidpf /*opaque UNUSED*/,
voidpf stream,
ZPOS64_T offset,
int origin)
{
QIODevice *iodevice = reinterpret_cast<QIODevice*>(stream);
if (iodevice->isSequential()) {
if (origin == ZLIB_FILEFUNC_SEEK_END
&& offset == 0) {
// sequential devices are always at end (needed in mdAppend)
return 0;
} else {
qWarning("qiodevice_seek_file_func() called for sequential device");
return -1;
}
}
qint64 qiodevice_seek_result=0;
int ret;
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset;
break;
case ZLIB_FILEFUNC_SEEK_END :
qiodevice_seek_result = ((QIODevice*)stream)->size() - offset;
break;
case ZLIB_FILEFUNC_SEEK_SET :
qiodevice_seek_result = offset;
break;
default:
return -1;
}
ret = !iodevice->seek(qiodevice_seek_result);
return ret;
}
int ZCALLBACK qiodevice_close_file_func (
voidpf opaque,
voidpf stream)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
delete d;
QIODevice *device = reinterpret_cast<QIODevice*>(stream);
#ifdef QUAZIP_QSAVEFILE_BUG_WORKAROUND
// QSaveFile terribly breaks the is-a idiom:
// it IS a QIODevice, but it is NOT compatible with it: close() is private
QSaveFile *file = qobject_cast<QSaveFile*>(device);
if (file != NULL) {
// We have to call the ugly commit() instead:
return file->commit() ? 0 : -1;
}
#endif
device->close();
return 0;
}
int ZCALLBACK qiodevice_fakeclose_file_func (
voidpf opaque,
voidpf /*stream*/)
{
QIODevice_descriptor *d = reinterpret_cast<QIODevice_descriptor*>(opaque);
delete d;
return 0;
}
int ZCALLBACK qiodevice_error_file_func (
voidpf /*opaque UNUSED*/,
voidpf /*stream UNUSED*/)
{
// can't check for error due to the QIODevice API limitation
return 0;
}
void fill_qiodevice_filefunc (
zlib_filefunc_def* pzlib_filefunc_def)
{
pzlib_filefunc_def->zopen_file = qiodevice_open_file_func;
pzlib_filefunc_def->zread_file = qiodevice_read_file_func;
pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func;
pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func;
pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func;
pzlib_filefunc_def->zclose_file = qiodevice_close_file_func;
pzlib_filefunc_def->zerror_file = qiodevice_error_file_func;
pzlib_filefunc_def->opaque = new QIODevice_descriptor;
}
void fill_qiodevice64_filefunc (
zlib_filefunc64_def* pzlib_filefunc_def)
{
// Open functions are the same for Qt.
pzlib_filefunc_def->zopen64_file = qiodevice_open_file_func;
pzlib_filefunc_def->zread_file = qiodevice_read_file_func;
pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func;
pzlib_filefunc_def->ztell64_file = qiodevice64_tell_file_func;
pzlib_filefunc_def->zseek64_file = qiodevice64_seek_file_func;
pzlib_filefunc_def->zclose_file = qiodevice_close_file_func;
pzlib_filefunc_def->zerror_file = qiodevice_error_file_func;
pzlib_filefunc_def->opaque = new QIODevice_descriptor;
pzlib_filefunc_def->zfakeclose_file = qiodevice_fakeclose_file_func;
}
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
{
p_filefunc64_32->zfile_func64.zopen64_file = NULL;
p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
p_filefunc64_32->zfile_func64.ztell64_file = NULL;
p_filefunc64_32->zfile_func64.zseek64_file = NULL;
p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
p_filefunc64_32->zfile_func64.zfakeclose_file = NULL;
p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
}
diff --git a/quazip/quaziodevice.cpp b/quazip/quaziodevice.cpp
--- a/quazip/quaziodevice.cpp
+++ b/quazip/quaziodevice.cpp
@@ -1,339 +1,349 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "quaziodevice.h"
#define QUAZIO_INBUFSIZE 4096
#define QUAZIO_OUTBUFSIZE 4096
/// \cond internal
class QuaZIODevicePrivate {
friend class QuaZIODevice;
- QuaZIODevicePrivate(QIODevice *io);
+ QuaZIODevicePrivate(QIODevice *io, QuaZIODevice *q);
~QuaZIODevicePrivate();
QIODevice *io;
+ QuaZIODevice *q;
z_stream zins;
z_stream zouts;
char *inBuf;
int inBufPos;
int inBufSize;
char *outBuf;
int outBufPos;
int outBufSize;
bool zBufError;
bool atEnd;
+ bool flush(int sync);
int doFlush(QString &error);
};
-QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io):
+QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io, QuaZIODevice *q):
io(io),
+ q(q),
inBuf(NULL),
inBufPos(0),
inBufSize(0),
outBuf(NULL),
outBufPos(0),
outBufSize(0),
zBufError(false),
atEnd(false)
{
zins.zalloc = (alloc_func) NULL;
zins.zfree = (free_func) NULL;
zins.opaque = NULL;
zouts.zalloc = (alloc_func) NULL;
zouts.zfree = (free_func) NULL;
zouts.opaque = NULL;
inBuf = new char[QUAZIO_INBUFSIZE];
outBuf = new char[QUAZIO_OUTBUFSIZE];
#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
debug.setFileName("debug.out");
debug.open(QIODevice::WriteOnly);
#endif
#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
indebug.setFileName("debug.in");
indebug.open(QIODevice::WriteOnly);
#endif
}
QuaZIODevicePrivate::~QuaZIODevicePrivate()
{
#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
debug.close();
#endif
#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
indebug.close();
#endif
if (inBuf != NULL)
delete[] inBuf;
if (outBuf != NULL)
- delete[] outBuf;
+ delete[] outBuf;
+}
+
+bool QuaZIODevicePrivate::flush(int sync)
+{
+ QString error;
+ if (doFlush(error) < 0) {
+ q->setErrorString(error);
+ return false;
+ }
+ // can't flush buffer, some data is still waiting
+ if (outBufPos < outBufSize)
+ return true;
+ Bytef c = 0;
+ zouts.next_in = &c; // fake input buffer
+ zouts.avail_in = 0; // of zero size
+ do {
+ zouts.next_out = (Bytef *) outBuf;
+ zouts.avail_out = QUAZIO_OUTBUFSIZE;
+ int result = deflate(&zouts, sync);
+ switch (result) {
+ case Z_OK:
+ case Z_STREAM_END:
+ outBufSize = (char *) zouts.next_out - outBuf;
+ if (doFlush(error) < 0) {
+ q->setErrorString(error);
+ return false;
+ }
+ if (outBufPos < outBufSize)
+ return true;
+ break;
+ case Z_BUF_ERROR: // nothing to write?
+ return true;
+ default:
+ q->setErrorString(QString::fromLocal8Bit(zouts.msg));
+ return false;
+ }
+ } while (zouts.avail_out == 0);
+ return true;
}
int QuaZIODevicePrivate::doFlush(QString &error)
{
int flushed = 0;
while (outBufPos < outBufSize) {
int more = io->write(outBuf + outBufPos, outBufSize - outBufPos);
if (more == -1) {
error = io->errorString();
return -1;
}
if (more == 0)
break;
outBufPos += more;
flushed += more;
}
if (outBufPos == outBufSize) {
outBufPos = outBufSize = 0;
}
return flushed;
}
/// \endcond
// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT
// #define QUAZIP_ZIODEVICE_DEBUG_INPUT
#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
-#include <QFile>
+#include <QtCore/QFile>
static QFile debug;
#endif
#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
-#include <QFile>
+#include <QtCore/QFile>
static QFile indebug;
#endif
QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent):
QIODevice(parent),
- d(new QuaZIODevicePrivate(io))
+ d(new QuaZIODevicePrivate(io, this))
{
connect(io, SIGNAL(readyRead()), SIGNAL(readyRead()));
}
QuaZIODevice::~QuaZIODevice()
{
if (isOpen())
close();
delete d;
}
QIODevice *QuaZIODevice::getIoDevice() const
{
return d->io;
}
bool QuaZIODevice::open(QIODevice::OpenMode mode)
{
if ((mode & QIODevice::Append) != 0) {
- setErrorString(trUtf8("QIODevice::Append is not supported for"
+ setErrorString(tr("QIODevice::Append is not supported for"
" QuaZIODevice"));
return false;
}
if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
- setErrorString(trUtf8("QIODevice::ReadWrite is not supported for"
+ setErrorString(tr("QIODevice::ReadWrite is not supported for"
" QuaZIODevice"));
return false;
}
if ((mode & QIODevice::ReadOnly) != 0) {
if (inflateInit(&d->zins) != Z_OK) {
- setErrorString(d->zins.msg);
+ setErrorString(QString::fromLocal8Bit(d->zins.msg));
return false;
}
}
if ((mode & QIODevice::WriteOnly) != 0) {
if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) {
- setErrorString(d->zouts.msg);
+ setErrorString(QString::fromLocal8Bit(d->zouts.msg));
return false;
}
}
return QIODevice::open(mode);
}
void QuaZIODevice::close()
{
if ((openMode() & QIODevice::ReadOnly) != 0) {
if (inflateEnd(&d->zins) != Z_OK) {
- setErrorString(d->zins.msg);
+ setErrorString(QString::fromLocal8Bit(d->zins.msg));
}
}
if ((openMode() & QIODevice::WriteOnly) != 0) {
- flush();
+ d->flush(Z_FINISH);
if (deflateEnd(&d->zouts) != Z_OK) {
- setErrorString(d->zouts.msg);
+ setErrorString(QString::fromLocal8Bit(d->zouts.msg));
}
}
QIODevice::close();
}
qint64 QuaZIODevice::readData(char *data, qint64 maxSize)
{
int read = 0;
while (read < maxSize) {
if (d->inBufPos == d->inBufSize) {
d->inBufPos = 0;
d->inBufSize = d->io->read(d->inBuf, QUAZIO_INBUFSIZE);
if (d->inBufSize == -1) {
d->inBufSize = 0;
setErrorString(d->io->errorString());
return -1;
}
if (d->inBufSize == 0)
break;
}
while (read < maxSize && d->inBufPos < d->inBufSize) {
d->zins.next_in = (Bytef *) (d->inBuf + d->inBufPos);
d->zins.avail_in = d->inBufSize - d->inBufPos;
d->zins.next_out = (Bytef *) (data + read);
d->zins.avail_out = (uInt) (maxSize - read); // hope it's less than 2GB
int more = 0;
switch (inflate(&d->zins, Z_SYNC_FLUSH)) {
case Z_OK:
read = (char *) d->zins.next_out - data;
d->inBufPos = (char *) d->zins.next_in - d->inBuf;
break;
case Z_STREAM_END:
read = (char *) d->zins.next_out - data;
d->inBufPos = (char *) d->zins.next_in - d->inBuf;
d->atEnd = true;
return read;
case Z_BUF_ERROR: // this should never happen, but just in case
if (!d->zBufError) {
qWarning("Z_BUF_ERROR detected with %d/%d in/out, weird",
d->zins.avail_in, d->zins.avail_out);
d->zBufError = true;
}
memmove(d->inBuf, d->inBuf + d->inBufPos, d->inBufSize - d->inBufPos);
d->inBufSize -= d->inBufPos;
d->inBufPos = 0;
more = d->io->read(d->inBuf + d->inBufSize, QUAZIO_INBUFSIZE - d->inBufSize);
if (more == -1) {
setErrorString(d->io->errorString());
return -1;
}
if (more == 0)
return read;
d->inBufSize += more;
break;
default:
setErrorString(QString::fromLocal8Bit(d->zins.msg));
return -1;
}
}
}
#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
indebug.write(data, read);
#endif
return read;
}
qint64 QuaZIODevice::writeData(const char *data, qint64 maxSize)
{
int written = 0;
QString error;
if (d->doFlush(error) == -1) {
setErrorString(error);
return -1;
}
while (written < maxSize) {
// there is some data waiting in the output buffer
if (d->outBufPos < d->outBufSize)
return written;
d->zouts.next_in = (Bytef *) (data + written);
d->zouts.avail_in = (uInt) (maxSize - written); // hope it's less than 2GB
d->zouts.next_out = (Bytef *) d->outBuf;
d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
switch (deflate(&d->zouts, Z_NO_FLUSH)) {
case Z_OK:
written = (char *) d->zouts.next_in - data;
d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
break;
default:
setErrorString(QString::fromLocal8Bit(d->zouts.msg));
return -1;
}
if (d->doFlush(error) == -1) {
setErrorString(error);
return -1;
}
}
#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
debug.write(data, written);
#endif
return written;
}
bool QuaZIODevice::flush()
{
- QString error;
- if (d->doFlush(error) < 0) {
- setErrorString(error);
- return false;
- }
- // can't flush buffer, some data is still waiting
- if (d->outBufPos < d->outBufSize)
- return true;
- Bytef c = 0;
- d->zouts.next_in = &c; // fake input buffer
- d->zouts.avail_in = 0; // of zero size
- do {
- d->zouts.next_out = (Bytef *) d->outBuf;
- d->zouts.avail_out = QUAZIO_OUTBUFSIZE;
- switch (deflate(&d->zouts, Z_SYNC_FLUSH)) {
- case Z_OK:
- d->outBufSize = (char *) d->zouts.next_out - d->outBuf;
- if (d->doFlush(error) < 0) {
- setErrorString(error);
- return false;
- }
- if (d->outBufPos < d->outBufSize)
- return true;
- break;
- case Z_BUF_ERROR: // nothing to write?
- return true;
- default:
- setErrorString(QString::fromLocal8Bit(d->zouts.msg));
- return false;
- }
- } while (d->zouts.avail_out == 0);
- return true;
+ return d->flush(Z_SYNC_FLUSH);
}
bool QuaZIODevice::isSequential() const
{
return true;
}
bool QuaZIODevice::atEnd() const
{
// Here we MUST check QIODevice::bytesAvailable() because WE
// might have reached the end, but QIODevice didn't--
// it could have simply pre-buffered all remaining data.
return (openMode() == NotOpen) || (QIODevice::bytesAvailable() == 0 && d->atEnd);
}
qint64 QuaZIODevice::bytesAvailable() const
{
// If we haven't recevied Z_STREAM_END, it means that
// we have at least one more input byte available.
// Plus whatever QIODevice has buffered.
return (d->atEnd ? 0 : 1) + QIODevice::bytesAvailable();
}
diff --git a/quazip/quaziodevice.h b/quazip/quaziodevice.h
--- a/quazip/quaziodevice.h
+++ b/quazip/quaziodevice.h
@@ -1,102 +1,103 @@
#ifndef QUAZIP_QUAZIODEVICE_H
#define QUAZIP_QUAZIODEVICE_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
-#include <QIODevice>
+#include <QtCore/QIODevice>
#include "quazip_global.h"
#include <zlib.h>
class QuaZIODevicePrivate;
/// A class to compress/decompress QIODevice.
/**
This class can be used to compress any data written to QIODevice or
decompress it back. Compressing data sent over a QTcpSocket is a good
example.
*/
class QUAZIP_EXPORT QuaZIODevice: public QIODevice {
+ friend class QuaZIODevicePrivate;
Q_OBJECT
public:
/// Constructor.
/**
\param io The QIODevice to read/write.
\param parent The parent object, as per QObject logic.
*/
QuaZIODevice(QIODevice *io, QObject *parent = NULL);
/// Destructor.
~QuaZIODevice();
/// Flushes data waiting to be written.
/**
Unfortunately, as QIODevice doesn't support flush() by itself, the
only thing this method does is write the compressed data into the
device using Z_SYNC_FLUSH mode. If you need the compressed data to
actually be flushed from the buffer of the underlying QIODevice, you
need to call its flush() method as well, providing it supports it
(like QTcpSocket does). Example:
\code
QuaZIODevice dev(&sock);
dev.open(QIODevice::Write);
dev.write(yourDataGoesHere);
dev.flush();
sock->flush(); // this actually sends data to network
\endcode
This may change in the future versions of QuaZIP by implementing an
ugly hack: trying to cast the QIODevice using qobject_cast to known
flush()-supporting subclasses, and calling flush if the resulting
pointer is not zero.
*/
virtual bool flush();
/// Opens the device.
/**
\param mode Neither QIODevice::ReadWrite nor QIODevice::Append are
not supported.
*/
virtual bool open(QIODevice::OpenMode mode);
/// Closes this device, but not the underlying one.
/**
The underlying QIODevice is not closed in case you want to write
something else to it.
*/
virtual void close();
/// Returns the underlying device.
QIODevice *getIoDevice() const;
/// Returns true.
virtual bool isSequential() const;
/// Returns true iff the end of the compressed stream is reached.
virtual bool atEnd() const;
/// Returns the number of the bytes buffered.
virtual qint64 bytesAvailable() const;
protected:
/// Implementation of QIODevice::readData().
virtual qint64 readData(char *data, qint64 maxSize);
/// Implementation of QIODevice::writeData().
virtual qint64 writeData(const char *data, qint64 maxSize);
private:
QuaZIODevicePrivate *d;
};
#endif // QUAZIP_QUAZIODEVICE_H
diff --git a/quazip/quazip.cpp b/quazip/quazip.cpp
--- a/quazip/quazip.cpp
+++ b/quazip/quazip.cpp
@@ -1,795 +1,846 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant, see
quazip/(un)zip.h files for details, basically it's zlib license.
**/
-#include <QFile>
-#include <QFlags>
-#include <QHash>
+#include <QtCore/QFile>
+#include <QtCore/QFlags>
+#include <QtCore/QHash>
#include "quazip.h"
+#define QUAZIP_OS_UNIX 3u
+
/// All the internal stuff for the QuaZip class.
/**
\internal
This class keeps all the private stuff for the QuaZip class so it can
be changed without breaking binary compatibility, according to the
Pimpl idiom.
*/
class QuaZipPrivate {
friend class QuaZip;
private:
Q_DISABLE_COPY(QuaZipPrivate)
/// The pointer to the corresponding QuaZip instance.
QuaZip *q;
- /// The codec for file names.
+ /// The codec for file names (used when UTF-8 is not enabled).
QTextCodec *fileNameCodec;
- /// The codec for comments.
+ /// The codec for comments (used when UTF-8 is not enabled).
QTextCodec *commentCodec;
/// The archive file name.
QString zipName;
/// The device to access the archive.
QIODevice *ioDevice;
/// The global comment.
QString comment;
/// The open mode.
QuaZip::Mode mode;
union {
/// The internal handle for UNZIP modes.
unzFile unzFile_f;
/// The internal handle for ZIP modes.
zipFile zipFile_f;
};
/// Whether a current file is set.
bool hasCurrentFile_f;
/// The last error.
int zipError;
/// Whether \ref QuaZip::setDataDescriptorWritingEnabled() "the data descriptor writing mode" is enabled.
bool dataDescriptorWritingEnabled;
/// The zip64 mode.
bool zip64;
/// The auto-close flag.
bool autoClose;
+ /// The UTF-8 flag.
+ bool utf8;
+ /// The OS code.
+ uint osCode;
inline QTextCodec *getDefaultFileNameCodec()
{
if (defaultFileNameCodec == NULL) {
return QTextCodec::codecForLocale();
} else {
return defaultFileNameCodec;
}
}
/// The constructor for the corresponding QuaZip constructor.
inline QuaZipPrivate(QuaZip *q):
q(q),
fileNameCodec(getDefaultFileNameCodec()),
commentCodec(QTextCodec::codecForLocale()),
ioDevice(NULL),
mode(QuaZip::mdNotOpen),
hasCurrentFile_f(false),
zipError(UNZ_OK),
dataDescriptorWritingEnabled(true),
zip64(false),
- autoClose(true)
+ autoClose(true),
+ utf8(false),
+ osCode(defaultOsCode)
{
unzFile_f = NULL;
zipFile_f = NULL;
lastMappedDirectoryEntry.num_of_file = 0;
lastMappedDirectoryEntry.pos_in_zip_directory = 0;
}
/// The constructor for the corresponding QuaZip constructor.
inline QuaZipPrivate(QuaZip *q, const QString &zipName):
q(q),
fileNameCodec(getDefaultFileNameCodec()),
commentCodec(QTextCodec::codecForLocale()),
zipName(zipName),
ioDevice(NULL),
mode(QuaZip::mdNotOpen),
hasCurrentFile_f(false),
zipError(UNZ_OK),
dataDescriptorWritingEnabled(true),
zip64(false),
- autoClose(true)
+ autoClose(true),
+ utf8(false),
+ osCode(defaultOsCode)
{
unzFile_f = NULL;
zipFile_f = NULL;
lastMappedDirectoryEntry.num_of_file = 0;
lastMappedDirectoryEntry.pos_in_zip_directory = 0;
}
/// The constructor for the corresponding QuaZip constructor.
inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice):
- q(q),
+ q(q),
fileNameCodec(getDefaultFileNameCodec()),
commentCodec(QTextCodec::codecForLocale()),
ioDevice(ioDevice),
mode(QuaZip::mdNotOpen),
hasCurrentFile_f(false),
zipError(UNZ_OK),
dataDescriptorWritingEnabled(true),
zip64(false),
- autoClose(true)
+ autoClose(true),
+ utf8(false),
+ osCode(defaultOsCode)
{
unzFile_f = NULL;
zipFile_f = NULL;
lastMappedDirectoryEntry.num_of_file = 0;
lastMappedDirectoryEntry.pos_in_zip_directory = 0;
}
/// Returns either a list of file names or a list of QuaZipFileInfo.
template<typename TFileInfo>
bool getFileInfoList(QList<TFileInfo> *result) const;
/// Stores map of filenames and file locations for unzipping
inline void clearDirectoryMap();
inline void addCurrentFileToDirectoryMap(const QString &fileName);
bool goToFirstUnmappedFile();
QHash<QString, unz64_file_pos> directoryCaseSensitive;
QHash<QString, unz64_file_pos> directoryCaseInsensitive;
unz64_file_pos lastMappedDirectoryEntry;
static QTextCodec *defaultFileNameCodec;
+ static uint defaultOsCode;
};
QTextCodec *QuaZipPrivate::defaultFileNameCodec = NULL;
+uint QuaZipPrivate::defaultOsCode = QUAZIP_OS_UNIX;
void QuaZipPrivate::clearDirectoryMap()
{
directoryCaseInsensitive.clear();
directoryCaseSensitive.clear();
lastMappedDirectoryEntry.num_of_file = 0;
lastMappedDirectoryEntry.pos_in_zip_directory = 0;
}
void QuaZipPrivate::addCurrentFileToDirectoryMap(const QString &fileName)
{
if (!hasCurrentFile_f || fileName.isEmpty()) {
return;
}
// Adds current file to filename map as fileName
unz64_file_pos fileDirectoryPos;
unzGetFilePos64(unzFile_f, &fileDirectoryPos);
directoryCaseSensitive.insert(fileName, fileDirectoryPos);
// Only add lowercase to directory map if not already there
// ensures only map the first one seen
QString lower = fileName.toLower();
if (!directoryCaseInsensitive.contains(lower))
directoryCaseInsensitive.insert(lower, fileDirectoryPos);
// Mark last one
if (fileDirectoryPos.pos_in_zip_directory > lastMappedDirectoryEntry.pos_in_zip_directory)
lastMappedDirectoryEntry = fileDirectoryPos;
}
bool QuaZipPrivate::goToFirstUnmappedFile()
{
zipError = UNZ_OK;
if (mode != QuaZip::mdUnzip) {
qWarning("QuaZipPrivate::goToNextUnmappedFile(): ZIP is not open in mdUnzip mode");
return false;
}
// If not mapped anything, go to beginning
if (lastMappedDirectoryEntry.pos_in_zip_directory == 0) {
unzGoToFirstFile(unzFile_f);
} else {
// Goto the last one mapped, plus one
unzGoToFilePos64(unzFile_f, &lastMappedDirectoryEntry);
unzGoToNextFile(unzFile_f);
}
hasCurrentFile_f=zipError==UNZ_OK;
if(zipError==UNZ_END_OF_LIST_OF_FILE)
zipError=UNZ_OK;
return hasCurrentFile_f;
}
QuaZip::QuaZip():
p(new QuaZipPrivate(this))
{
}
QuaZip::QuaZip(const QString& zipName):
p(new QuaZipPrivate(this, zipName))
{
}
QuaZip::QuaZip(QIODevice *ioDevice):
p(new QuaZipPrivate(this, ioDevice))
{
}
QuaZip::~QuaZip()
{
if(isOpen())
close();
delete p;
}
bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi)
{
p->zipError=UNZ_OK;
if(isOpen()) {
qWarning("QuaZip::open(): ZIP already opened");
return false;
}
QIODevice *ioDevice = p->ioDevice;
if (ioDevice == NULL) {
if (p->zipName.isEmpty()) {
qWarning("QuaZip::open(): set either ZIP file name or IO device first");
return false;
} else {
ioDevice = new QFile(p->zipName);
}
}
unsigned flags = 0;
switch(mode) {
case mdUnzip:
if (ioApi == NULL) {
if (p->autoClose)
flags |= UNZ_AUTO_CLOSE;
p->unzFile_f=unzOpenInternal(ioDevice, NULL, 1, flags);
} else {
// QuaZIP pre-zip64 compatibility mode
p->unzFile_f=unzOpen2(ioDevice, ioApi);
if (p->unzFile_f != NULL) {
if (p->autoClose) {
unzSetFlags(p->unzFile_f, UNZ_AUTO_CLOSE);
} else {
unzClearFlags(p->unzFile_f, UNZ_AUTO_CLOSE);
}
}
}
if(p->unzFile_f!=NULL) {
if (ioDevice->isSequential()) {
unzClose(p->unzFile_f);
if (!p->zipName.isEmpty())
delete ioDevice;
qWarning("QuaZip::open(): "
"only mdCreate can be used with "
"sequential devices");
return false;
}
p->mode=mode;
p->ioDevice = ioDevice;
return true;
} else {
p->zipError=UNZ_OPENERROR;
if (!p->zipName.isEmpty())
delete ioDevice;
return false;
}
case mdCreate:
case mdAppend:
case mdAdd:
if (ioApi == NULL) {
if (p->autoClose)
flags |= ZIP_AUTO_CLOSE;
if (p->dataDescriptorWritingEnabled)
flags |= ZIP_WRITE_DATA_DESCRIPTOR;
+ if (p->utf8)
+ flags |= ZIP_ENCODING_UTF8;
p->zipFile_f=zipOpen3(ioDevice,
mode==mdCreate?APPEND_STATUS_CREATE:
mode==mdAppend?APPEND_STATUS_CREATEAFTER:
APPEND_STATUS_ADDINZIP,
NULL, NULL, flags);
} else {
// QuaZIP pre-zip64 compatibility mode
p->zipFile_f=zipOpen2(ioDevice,
mode==mdCreate?APPEND_STATUS_CREATE:
mode==mdAppend?APPEND_STATUS_CREATEAFTER:
APPEND_STATUS_ADDINZIP,
NULL,
ioApi);
if (p->zipFile_f != NULL) {
zipSetFlags(p->zipFile_f, flags);
}
}
if(p->zipFile_f!=NULL) {
if (ioDevice->isSequential()) {
if (mode != mdCreate) {
zipClose(p->zipFile_f, NULL);
qWarning("QuaZip::open(): "
"only mdCreate can be used with "
"sequential devices");
if (!p->zipName.isEmpty())
delete ioDevice;
return false;
}
zipSetFlags(p->zipFile_f, ZIP_SEQUENTIAL);
}
p->mode=mode;
p->ioDevice = ioDevice;
return true;
} else {
p->zipError=UNZ_OPENERROR;
if (!p->zipName.isEmpty())
delete ioDevice;
return false;
}
default:
qWarning("QuaZip::open(): unknown mode: %d", (int)mode);
if (!p->zipName.isEmpty())
delete ioDevice;
return false;
break;
}
}
void QuaZip::close()
{
p->zipError=UNZ_OK;
switch(p->mode) {
case mdNotOpen:
qWarning("QuaZip::close(): ZIP is not open");
return;
case mdUnzip:
p->zipError=unzClose(p->unzFile_f);
break;
case mdCreate:
case mdAppend:
case mdAdd:
- p->zipError=zipClose(p->zipFile_f,
- p->comment.isNull() ? NULL
- : p->commentCodec->fromUnicode(p->comment).constData());
+ p->zipError=zipClose(p->zipFile_f, p->comment.isNull() ? NULL : isUtf8Enabled()
+ ? p->comment.toUtf8().constData()
+ : p->commentCodec->fromUnicode(p->comment).constData());
break;
default:
qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode);
return;
}
// opened by name, need to delete the internal IO device
if (!p->zipName.isEmpty()) {
delete p->ioDevice;
p->ioDevice = NULL;
}
p->clearDirectoryMap();
if(p->zipError==UNZ_OK)
p->mode=mdNotOpen;
}
void QuaZip::setZipName(const QString& zipName)
{
if(isOpen()) {
qWarning("QuaZip::setZipName(): ZIP is already open!");
return;
}
p->zipName=zipName;
p->ioDevice = NULL;
}
void QuaZip::setIoDevice(QIODevice *ioDevice)
{
if(isOpen()) {
qWarning("QuaZip::setIoDevice(): ZIP is already open!");
return;
}
p->ioDevice = ioDevice;
p->zipName = QString();
}
int QuaZip::getEntriesCount()const
{
QuaZip *fakeThis=(QuaZip*)this; // non-const
fakeThis->p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode");
return -1;
}
unz_global_info64 globalInfo;
if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK)
return p->zipError;
return (int)globalInfo.number_entry;
}
QString QuaZip::getComment()const
{
QuaZip *fakeThis=(QuaZip*)this; // non-const
fakeThis->p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode");
return QString();
}
unz_global_info64 globalInfo;
QByteArray comment;
if((fakeThis->p->zipError=unzGetGlobalInfo64(p->unzFile_f, &globalInfo))!=UNZ_OK)
return QString();
comment.resize(globalInfo.size_comment);
if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0)
return QString();
fakeThis->p->zipError = UNZ_OK;
- return p->commentCodec->toUnicode(comment);
+ unsigned flags = 0;
+ return (unzGetFileFlags(p->unzFile_f, &flags) == UNZ_OK) && (flags & UNZ_ENCODING_UTF8)
+ ? QString::fromUtf8(comment) : p->commentCodec->toUnicode(comment);
}
bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs)
{
p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode");
return false;
}
if(fileName.isEmpty()) {
p->hasCurrentFile_f=false;
return true;
}
// Unicode-aware reimplementation of the unzLocateFile function
if(p->unzFile_f==NULL) {
p->zipError=UNZ_PARAMERROR;
return false;
}
if(fileName.length()>MAX_FILE_NAME_LENGTH) {
p->zipError=UNZ_PARAMERROR;
return false;
}
// Find the file by name
bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive;
QString lower, current;
if(!sens) lower=fileName.toLower();
p->hasCurrentFile_f=false;
// Check the appropriate Map
unz64_file_pos fileDirPos;
fileDirPos.pos_in_zip_directory = 0;
if (sens) {
if (p->directoryCaseSensitive.contains(fileName))
fileDirPos = p->directoryCaseSensitive.value(fileName);
} else {
if (p->directoryCaseInsensitive.contains(lower))
fileDirPos = p->directoryCaseInsensitive.value(lower);
}
if (fileDirPos.pos_in_zip_directory != 0) {
p->zipError = unzGoToFilePos64(p->unzFile_f, &fileDirPos);
p->hasCurrentFile_f = p->zipError == UNZ_OK;
}
if (p->hasCurrentFile_f)
return p->hasCurrentFile_f;
// Not mapped yet, start from where we have got to so far
for(bool more=p->goToFirstUnmappedFile(); more; more=goToNextFile()) {
current=getCurrentFileName();
if(current.isEmpty()) return false;
if(sens) {
if(current==fileName) break;
} else {
if(current.toLower()==lower) break;
}
}
return p->hasCurrentFile_f;
}
bool QuaZip::goToFirstFile()
{
p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
return false;
}
p->zipError=unzGoToFirstFile(p->unzFile_f);
p->hasCurrentFile_f=p->zipError==UNZ_OK;
return p->hasCurrentFile_f;
}
bool QuaZip::goToNextFile()
{
p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
return false;
}
p->zipError=unzGoToNextFile(p->unzFile_f);
p->hasCurrentFile_f=p->zipError==UNZ_OK;
if(p->zipError==UNZ_END_OF_LIST_OF_FILE)
p->zipError=UNZ_OK;
return p->hasCurrentFile_f;
}
bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const
{
QuaZipFileInfo64 info64;
if (info == NULL) { // Very unlikely because of the overloads
return false;
}
if (getCurrentFileInfo(&info64)) {
info64.toQuaZipFileInfo(*info);
return true;
} else {
return false;
}
}
bool QuaZip::getCurrentFileInfo(QuaZipFileInfo64 *info)const
{
QuaZip *fakeThis=(QuaZip*)this; // non-const
fakeThis->p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode");
return false;
}
unz_file_info64 info_z;
QByteArray fileName;
QByteArray extra;
QByteArray comment;
if(info==NULL) return false;
if(!isOpen()||!hasCurrentFile()) return false;
if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK)
return false;
fileName.resize(info_z.size_filename);
extra.resize(info_z.size_file_extra);
comment.resize(info_z.size_file_comment);
if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL,
fileName.data(), fileName.size(),
extra.data(), extra.size(),
comment.data(), comment.size()))!=UNZ_OK)
return false;
info->versionCreated=info_z.version;
info->versionNeeded=info_z.version_needed;
info->flags=info_z.flag;
info->method=info_z.compression_method;
info->crc=info_z.crc;
info->compressedSize=info_z.compressed_size;
info->uncompressedSize=info_z.uncompressed_size;
info->diskNumberStart=info_z.disk_num_start;
info->internalAttr=info_z.internal_fa;
info->externalAttr=info_z.external_fa;
- info->name=p->fileNameCodec->toUnicode(fileName);
- info->comment=p->commentCodec->toUnicode(comment);
+ info->name=(info->flags & UNZ_ENCODING_UTF8) ? QString::fromUtf8(fileName) : p->fileNameCodec->toUnicode(fileName);
+ info->comment=(info->flags & UNZ_ENCODING_UTF8) ? QString::fromUtf8(comment) : p->commentCodec->toUnicode(comment);
info->extra=extra;
info->dateTime=QDateTime(
QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday),
QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec));
// Add to directory map
p->addCurrentFileToDirectoryMap(info->name);
return true;
}
QString QuaZip::getCurrentFileName()const
{
QuaZip *fakeThis=(QuaZip*)this; // non-const
fakeThis->p->zipError=UNZ_OK;
if(p->mode!=mdUnzip) {
qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode");
return QString();
}
if(!isOpen()||!hasCurrentFile()) return QString();
QByteArray fileName(MAX_FILE_NAME_LENGTH, 0);
- if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, NULL, fileName.data(), fileName.size(),
+ unz_file_info64 file_info;
+ if((fakeThis->p->zipError=unzGetCurrentFileInfo64(p->unzFile_f, &file_info, fileName.data(), fileName.size(),
NULL, 0, NULL, 0))!=UNZ_OK)
return QString();
- QString result = p->fileNameCodec->toUnicode(fileName.constData());
+ fileName.resize(file_info.size_filename);
+ QString result = (file_info.flag & UNZ_ENCODING_UTF8)
+ ? QString::fromUtf8(fileName) : p->fileNameCodec->toUnicode(fileName);
if (result.isEmpty())
return result;
// Add to directory map
p->addCurrentFileToDirectoryMap(result);
return result;
}
void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec)
{
p->fileNameCodec=fileNameCodec;
}
void QuaZip::setFileNameCodec(const char *fileNameCodecName)
{
- p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName);
+ p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName);
+}
+
+void QuaZip::setOsCode(uint osCode)
+{
+ p->osCode = osCode;
+}
+
+uint QuaZip::getOsCode() const
+{
+ return p->osCode;
}
QTextCodec *QuaZip::getFileNameCodec()const
{
return p->fileNameCodec;
}
void QuaZip::setCommentCodec(QTextCodec *commentCodec)
{
p->commentCodec=commentCodec;
}
void QuaZip::setCommentCodec(const char *commentCodecName)
{
p->commentCodec=QTextCodec::codecForName(commentCodecName);
}
QTextCodec *QuaZip::getCommentCodec()const
{
return p->commentCodec;
}
QString QuaZip::getZipName() const
{
return p->zipName;
}
QIODevice *QuaZip::getIoDevice() const
{
if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice
return NULL;
return p->ioDevice;
}
QuaZip::Mode QuaZip::getMode()const
{
return p->mode;
}
bool QuaZip::isOpen()const
{
return p->mode!=mdNotOpen;
}
int QuaZip::getZipError() const
{
return p->zipError;
}
void QuaZip::setComment(const QString& comment)
{
p->comment=comment;
}
bool QuaZip::hasCurrentFile()const
{
return p->hasCurrentFile_f;
}
unzFile QuaZip::getUnzFile()
{
return p->unzFile_f;
}
zipFile QuaZip::getZipFile()
{
return p->zipFile_f;
}
void QuaZip::setDataDescriptorWritingEnabled(bool enabled)
{
p->dataDescriptorWritingEnabled = enabled;
}
bool QuaZip::isDataDescriptorWritingEnabled() const
{
return p->dataDescriptorWritingEnabled;
}
template<typename TFileInfo>
TFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok);
template<>
QuaZipFileInfo QuaZip_getFileInfo(QuaZip *zip, bool *ok)
{
QuaZipFileInfo info;
*ok = zip->getCurrentFileInfo(&info);
return info;
}
template<>
QuaZipFileInfo64 QuaZip_getFileInfo(QuaZip *zip, bool *ok)
{
QuaZipFileInfo64 info;
*ok = zip->getCurrentFileInfo(&info);
return info;
}
template<>
QString QuaZip_getFileInfo(QuaZip *zip, bool *ok)
{
QString name = zip->getCurrentFileName();
*ok = !name.isEmpty();
return name;
}
template<typename TFileInfo>
bool QuaZipPrivate::getFileInfoList(QList<TFileInfo> *result) const
{
QuaZipPrivate *fakeThis=const_cast<QuaZipPrivate*>(this);
fakeThis->zipError=UNZ_OK;
if (mode!=QuaZip::mdUnzip) {
qWarning("QuaZip::getFileNameList/getFileInfoList(): "
"ZIP is not open in mdUnzip mode");
return false;
}
QString currentFile;
if (q->hasCurrentFile()) {
currentFile = q->getCurrentFileName();
}
if (q->goToFirstFile()) {
do {
bool ok;
result->append(QuaZip_getFileInfo<TFileInfo>(q, &ok));
if (!ok)
return false;
} while (q->goToNextFile());
}
if (zipError != UNZ_OK)
return false;
if (currentFile.isEmpty()) {
if (!q->goToFirstFile())
return false;
} else {
if (!q->setCurrentFile(currentFile))
return false;
}
return true;
}
QStringList QuaZip::getFileNameList() const
{
QStringList list;
if (p->getFileInfoList(&list))
return list;
else
return QStringList();
}
QList<QuaZipFileInfo> QuaZip::getFileInfoList() const
{
QList<QuaZipFileInfo> list;
if (p->getFileInfoList(&list))
return list;
else
return QList<QuaZipFileInfo>();
}
QList<QuaZipFileInfo64> QuaZip::getFileInfoList64() const
{
QList<QuaZipFileInfo64> list;
if (p->getFileInfoList(&list))
return list;
else
return QList<QuaZipFileInfo64>();
}
Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs)
{
if (cs == csDefault) {
#ifdef Q_OS_WIN
return Qt::CaseInsensitive;
#else
return Qt::CaseSensitive;
#endif
} else {
return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
}
}
void QuaZip::setDefaultFileNameCodec(QTextCodec *codec)
{
QuaZipPrivate::defaultFileNameCodec = codec;
}
void QuaZip::setDefaultFileNameCodec(const char *codecName)
{
setDefaultFileNameCodec(QTextCodec::codecForName(codecName));
}
+void QuaZip::setDefaultOsCode(uint osCode)
+{
+ QuaZipPrivate::defaultOsCode = osCode;
+}
+
+uint QuaZip::getDefaultOsCode()
+{
+ return QuaZipPrivate::defaultOsCode;
+}
+
void QuaZip::setZip64Enabled(bool zip64)
{
p->zip64 = zip64;
}
bool QuaZip::isZip64Enabled() const
{
return p->zip64;
}
+void QuaZip::setUtf8Enabled(bool utf8)
+{
+ p->utf8 = utf8;
+}
+
+bool QuaZip::isUtf8Enabled() const
+{
+ return p->utf8;
+}
+
bool QuaZip::isAutoClose() const
{
return p->autoClose;
}
void QuaZip::setAutoClose(bool autoClose) const
{
p->autoClose = autoClose;
}
diff --git a/quazip/quazip.h b/quazip/quazip.h
--- a/quazip/quazip.h
+++ b/quazip/quazip.h
@@ -1,571 +1,611 @@
#ifndef QUA_ZIP_H
#define QUA_ZIP_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant, see
quazip/(un)zip.h files for details, basically it's zlib license.
**/
-#include <QString>
-#include <QStringList>
-#include <QTextCodec>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QTextCodec>
#include "zip.h"
#include "unzip.h"
#include "quazip_global.h"
#include "quazipfileinfo.h"
// just in case it will be defined in the later versions of the ZIP/UNZIP
#ifndef UNZ_OPENERROR
// define additional error code
#define UNZ_OPENERROR -1000
#endif
class QuaZipPrivate;
/// ZIP archive.
/** \class QuaZip quazip.h <quazip/quazip.h>
* This class implements basic interface to the ZIP archive. It can be
* used to read table contents of the ZIP archive and retreiving
* information about the files inside it.
*
* You can also use this class to open files inside archive by passing
* pointer to the instance of this class to the constructor of the
* QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*)
* for the possible pitfalls.
*
* This class is indended to provide interface to the ZIP subpackage of
* the ZIP/UNZIP package as well as to the UNZIP subpackage. But
* currently it supports only UNZIP.
*
* The use of this class is simple - just create instance using
* constructor, then set ZIP archive file name using setFile() function
* (if you did not passed the name to the constructor), then open() and
* then use different functions to work with it! Well, if you are
* paranoid, you may also wish to call close before destructing the
* instance, to check for errors on close.
*
* You may also use getUnzFile() and getZipFile() functions to get the
* ZIP archive handle and use it with ZIP/UNZIP package API directly.
*
* This class supports localized file names inside ZIP archive, but you
* have to set up proper codec with setCodec() function. By default,
* locale codec will be used, which is probably ok for UNIX systems, but
* will almost certainly fail with ZIP archives created in Windows. This
* is because Windows ZIP programs have strange habit of using DOS
* encoding for file names in ZIP archives. For example, ZIP archive
* with cyrillic names created in Windows will have file names in \c
* IBM866 encoding instead of \c WINDOWS-1251. I think that calling one
* function is not much trouble, but for true platform independency it
* would be nice to have some mechanism for file name encoding auto
* detection using locale information. Does anyone know a good way to do
* it?
**/
class QUAZIP_EXPORT QuaZip {
friend class QuaZipPrivate;
public:
/// Useful constants.
enum Constants {
MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from
\c UNZ_MAXFILENAMEINZIP constant in
unzip.c. */
};
/// Open mode of the ZIP file.
enum Mode {
mdNotOpen, ///< ZIP file is not open. This is the initial mode.
mdUnzip, ///< ZIP file is open for reading files inside it.
mdCreate, ///< ZIP file was created with open() call.
mdAppend, /**< ZIP file was opened in append mode. This refers to
* \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package
* and means that zip is appended to some existing file
* what is useful when that file contains
* self-extractor code. This is obviously \em not what
* you whant to use to add files to the existing ZIP
* archive.
**/
mdAdd ///< ZIP file was opened for adding files in the archive.
};
/// Case sensitivity for the file names.
/** This is what you specify when accessing files in the archive.
* Works perfectly fine with any characters thanks to Qt's great
* unicode support. This is different from ZIP/UNZIP API, where
* only US-ASCII characters was supported.
**/
enum CaseSensitivity {
csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows.
csSensitive=1, ///< Case sensitive.
csInsensitive=2 ///< Case insensitive.
};
/// Returns the actual case sensitivity for the specified QuaZIP one.
/**
\param cs The value to convert.
\returns If CaseSensitivity::csDefault, then returns the default
file name case sensitivity for the platform. Otherwise, just
returns the appropriate value from the Qt::CaseSensitivity enum.
*/
static Qt::CaseSensitivity convertCaseSensitivity(
CaseSensitivity cs);
private:
QuaZipPrivate *p;
// not (and will not be) implemented
QuaZip(const QuaZip& that);
// not (and will not be) implemented
QuaZip& operator=(const QuaZip& that);
public:
/// Constructs QuaZip object.
/** Call setName() before opening constructed object. */
QuaZip();
/// Constructs QuaZip object associated with ZIP file \a zipName.
QuaZip(const QString& zipName);
/// Constructs QuaZip object associated with ZIP file represented by \a ioDevice.
/** The IO device must be seekable, otherwise an error will occur when opening. */
QuaZip(QIODevice *ioDevice);
/// Destroys QuaZip object.
/** Calls close() if necessary. */
~QuaZip();
/// Opens ZIP file.
/**
* Argument \a mode specifies open mode of the ZIP archive. See Mode
* for details. Note that there is zipOpen2() function in the
* ZIP/UNZIP API which accepts \a globalcomment argument, but it
* does not use it anywhere, so this open() function does not have this
* argument. See setComment() if you need to set global comment.
*
* If the ZIP file is accessed via explicitly set QIODevice, then
* this device is opened in the necessary mode. If the device was
* already opened by some other means, then QuaZIP checks if the
* open mode is compatible to the mode needed for the requested operation.
* If necessary, seeking is performed to position the device properly.
*
* \return \c true if successful, \c false otherwise.
*
* \note ZIP/UNZIP API open calls do not return error code - they
* just return \c NULL indicating an error. But to make things
* easier, quazip.h header defines additional error code \c
* UNZ_ERROROPEN and getZipError() will return it if the open call
* of the ZIP/UNZIP API returns \c NULL.
*
* Argument \a ioApi specifies IO function set for ZIP/UNZIP
* package to use. See unzip.h, zip.h and ioapi.h for details. Note
* that IO API for QuaZip is different from the original package.
* The file path argument was changed to be of type \c voidpf, and
* QuaZip passes a QIODevice pointer there. This QIODevice is either
* set explicitly via setIoDevice() or the QuaZip(QIODevice*)
* constructor, or it is created internally when opening the archive
* by its file name. The default API (qioapi.cpp) just delegates
* everything to the QIODevice API. Not only this allows to use a
* QIODevice instead of file name, but also has a nice side effect
* of raising the file size limit from 2G to 4G (in non-zip64 archives).
*
* \note If the zip64 support is needed, the ioApi argument \em must be NULL
* because due to the backwards compatibility issues it can be used to
* provide a 32-bit API only.
*
* \note If the \ref QuaZip::setAutoClose() "no-auto-close" feature is used,
* then the \a ioApi argument \em should be NULL because the old API
* doesn't support the 'fake close' operation, causing slight memory leaks
* and other possible troubles (like closing the output device in case
* when an error occurs during opening).
*
* In short: just forget about the \a ioApi argument and you'll be
* fine.
**/
bool open(Mode mode, zlib_filefunc_def *ioApi =NULL);
/// Closes ZIP file.
/** Call getZipError() to determine if the close was successful.
*
* If the file was opened by name, then the underlying QIODevice is closed
* and deleted.
*
* If the underlying QIODevice was set explicitly using setIoDevice() or
* the appropriate constructor, then it is closed if the auto-close flag
* is set (which it is by default). Call setAutoClose() to clear the
* auto-close flag if this behavior is undesirable.
*
* Since Qt 5.1, the QSaveFile was introduced. It breaks the QIODevice API
* by making close() private and crashing the application if it is called
* from the base class where it is public. It is an excellent example
* of poor design that illustrates why you should never ever break
* an is-a relationship between the base class and a subclass. QuaZIP
* works around this bug by checking if the QIODevice is an instance
* of QSaveFile, using qobject_cast<>, and if it is, calls
* QSaveFile::commit() instead of close(). It is a really ugly hack,
* but at least it makes your programs work instead of crashing. Note that
* if the auto-close flag is cleared, then this is a non-issue, and
* commit() isn't called.
*/
void close();
/// Sets the codec used to encode/decode file names inside archive.
/** This is necessary to access files in the ZIP archive created
* under Windows with non-latin characters in file names. For
* example, file names with cyrillic letters will be in \c IBM866
* encoding.
**/
void setFileNameCodec(QTextCodec *fileNameCodec);
/// Sets the codec used to encode/decode file names inside archive.
/** \overload
* Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName));
**/
void setFileNameCodec(const char *fileNameCodecName);
+ /// Sets the OS code (highest 8 bits of the “version made by” field) for new files.
+ /** There is currently no way to specify this for each file individually,
+ except by calling this function before opening each file. If this function is not called,
+ then the default OS code will be used. The default code is set by calling
+ setDefaultOsCode(). The default value at the moment of QuaZip creation will be used. */
+ void setOsCode(uint osCode);
+ /// Returns the OS code for new files.
+ uint getOsCode() const;
/// Returns the codec used to encode/decode comments inside archive.
QTextCodec* getFileNameCodec() const;
/// Sets the codec used to encode/decode comments inside archive.
/** This codec defaults to locale codec, which is probably ok.
**/
void setCommentCodec(QTextCodec *commentCodec);
/// Sets the codec used to encode/decode comments inside archive.
/** \overload
* Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName));
**/
void setCommentCodec(const char *commentCodecName);
/// Returns the codec used to encode/decode comments inside archive.
QTextCodec* getCommentCodec() const;
/// Returns the name of the ZIP file.
/** Returns null string if no ZIP file name has been set, for
* example when the QuaZip instance is set up to use a QIODevice
* instead.
* \sa setZipName(), setIoDevice(), getIoDevice()
**/
QString getZipName() const;
/// Sets the name of the ZIP file.
/** Does nothing if the ZIP file is open.
*
* Does not reset error code returned by getZipError().
* \sa setIoDevice(), getIoDevice(), getZipName()
**/
void setZipName(const QString& zipName);
/// Returns the device representing this ZIP file.
/** Returns null string if no device has been set explicitly, for
* example when opening a ZIP file by name.
* \sa setIoDevice(), getZipName(), setZipName()
**/
QIODevice *getIoDevice() const;
/// Sets the device representing the ZIP file.
/** Does nothing if the ZIP file is open.
*
* Does not reset error code returned by getZipError().
* \sa getIoDevice(), getZipName(), setZipName()
**/
void setIoDevice(QIODevice *ioDevice);
/// Returns the mode in which ZIP file was opened.
Mode getMode() const;
/// Returns \c true if ZIP file is open, \c false otherwise.
bool isOpen() const;
/// Returns the error code of the last operation.
/** Returns \c UNZ_OK if the last operation was successful.
*
* Error code resets to \c UNZ_OK every time you call any function
* that accesses something inside ZIP archive, even if it is \c
* const (like getEntriesCount()). open() and close() calls reset
* error code too. See documentation for the specific functions for
* details on error detection.
**/
int getZipError() const;
/// Returns number of the entries in the ZIP central directory.
/** Returns negative error code in the case of error. The same error
* code will be returned by subsequent getZipError() call.
**/
int getEntriesCount() const;
/// Returns global comment in the ZIP file.
QString getComment() const;
/// Sets the global comment in the ZIP file.
/** The comment will be written to the archive on close operation.
* QuaZip makes a distinction between a null QByteArray() comment
* and an empty &quot;&quot; comment in the QuaZip::mdAdd mode.
* A null comment is the default and it means &quot;don't change
* the comment&quot;. An empty comment removes the original comment.
*
* \sa open()
**/
void setComment(const QString& comment);
/// Sets the current file to the first file in the archive.
/** Returns \c true on success, \c false otherwise. Call
* getZipError() to get the error code.
**/
bool goToFirstFile();
/// Sets the current file to the next file in the archive.
/** Returns \c true on success, \c false otherwise. Call
* getZipError() to determine if there was an error.
*
* Should be used only in QuaZip::mdUnzip mode.
*
* \note If the end of file was reached, getZipError() will return
* \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make
* things like this easier:
* \code
* for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
* // do something
* }
* if(zip.getZipError()==UNZ_OK) {
* // ok, there was no error
* }
* \endcode
**/
bool goToNextFile();
/// Sets current file by its name.
/** Returns \c true if successful, \c false otherwise. Argument \a
* cs specifies case sensitivity of the file name. Call
* getZipError() in the case of a failure to get error code.
*
* This is not a wrapper to unzLocateFile() function. That is
* because I had to implement locale-specific case-insensitive
* comparison.
*
* Here are the differences from the original implementation:
*
* - If the file was not found, error code is \c UNZ_OK, not \c
* UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()).
* - If this function fails, it unsets the current file rather than
* resetting it back to what it was before the call.
*
* If \a fileName is null string then this function unsets the
* current file and return \c true. Note that you should close the
* file first if it is open! See
* QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details.
*
* Should be used only in QuaZip::mdUnzip mode.
*
* \sa setFileNameCodec(), CaseSensitivity
**/
bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault);
/// Returns \c true if the current file has been set.
bool hasCurrentFile() const;
/// Retrieves information about the current file.
/** Fills the structure pointed by \a info. Returns \c true on
* success, \c false otherwise. In the latter case structure pointed
* by \a info remains untouched. If there was an error,
* getZipError() returns error code.
*
* Should be used only in QuaZip::mdUnzip mode.
*
* Does nothing and returns \c false in any of the following cases.
* - ZIP is not open;
* - ZIP does not have current file.
*
* In both cases getZipError() returns \c UNZ_OK since there
* is no ZIP/UNZIP API call.
*
* This overload doesn't support zip64, but will work OK on zip64 archives
* except that if one of the sizes (compressed or uncompressed) is greater
* than 0xFFFFFFFFu, it will be set to exactly 0xFFFFFFFFu.
*
* \sa getCurrentFileInfo(QuaZipFileInfo64* info)const
* \sa QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo&)const
**/
bool getCurrentFileInfo(QuaZipFileInfo* info)const;
/// Retrieves information about the current file.
/** \overload
*
* This function supports zip64. If the archive doesn't use zip64, it is
* completely equivalent to getCurrentFileInfo(QuaZipFileInfo* info)
* except for the argument type.
*
* \sa
**/
bool getCurrentFileInfo(QuaZipFileInfo64* info)const;
/// Returns the current file name.
/** Equivalent to calling getCurrentFileInfo() and then getting \c
* name field of the QuaZipFileInfo structure, but faster and more
* convenient.
*
* Should be used only in QuaZip::mdUnzip mode.
**/
QString getCurrentFileName()const;
/// Returns \c unzFile handle.
/** You can use this handle to directly call UNZIP part of the
* ZIP/UNZIP package functions (see unzip.h).
*
* \warning When using the handle returned by this function, please
* keep in mind that QuaZip class is unable to detect any changes
* you make in the ZIP file state (e. g. changing current file, or
* closing the handle). So please do not do anything with this
* handle that is possible to do with the functions of this class.
* Or at least return the handle in the original state before
* calling some another function of this class (including implicit
* destructor calls and calls from the QuaZipFile objects that refer
* to this QuaZip instance!). So if you have changed the current
* file in the ZIP archive - then change it back or you may
* experience some strange behavior or even crashes.
**/
unzFile getUnzFile();
/// Returns \c zipFile handle.
/** You can use this handle to directly call ZIP part of the
* ZIP/UNZIP package functions (see zip.h). Warnings about the
* getUnzFile() function also apply to this function.
**/
zipFile getZipFile();
/// Changes the data descriptor writing mode.
/**
According to the ZIP format specification, a file inside archive
may have a data descriptor immediately following the file
data. This is reflected by a special flag in the local file header
and in the central directory. By default, QuaZIP sets this flag
and writes the data descriptor unless both method and level were
set to 0, in which case it operates in 1.0-compatible mode and
never writes data descriptors.
By setting this flag to false, it is possible to disable data
descriptor writing, thus increasing compatibility with archive
readers that don't understand this feature of the ZIP file format.
Setting this flag affects all the QuaZipFile instances that are
opened after this flag is set.
The data descriptor writing mode is enabled by default.
Note that if the ZIP archive is written into a QIODevice for which
QIODevice::isSequential() returns \c true, then the data descriptor
is mandatory and will be written even if this flag is set to false.
\param enabled If \c true, enable local descriptor writing,
disable it otherwise.
\sa QuaZipFile::isDataDescriptorWritingEnabled()
*/
void setDataDescriptorWritingEnabled(bool enabled);
/// Returns the data descriptor default writing mode.
/**
\sa setDataDescriptorWritingEnabled()
*/
bool isDataDescriptorWritingEnabled() const;
/// Returns a list of files inside the archive.
/**
\return A list of file names or an empty list if there
was an error or if the archive is empty (call getZipError() to
figure out which).
\sa getFileInfoList()
*/
QStringList getFileNameList() const;
/// Returns information list about all files inside the archive.
/**
\return A list of QuaZipFileInfo objects or an empty list if there
was an error or if the archive is empty (call getZipError() to
figure out which).
This function doesn't support zip64, but will still work with zip64
archives, converting results using QuaZipFileInfo64::toQuaZipFileInfo().
If all file sizes are below 4 GB, it will work just fine.
\sa getFileNameList()
\sa getFileInfoList64()
*/
QList<QuaZipFileInfo> getFileInfoList() const;
/// Returns information list about all files inside the archive.
/**
\overload
This function supports zip64.
\sa getFileNameList()
\sa getFileInfoList()
*/
QList<QuaZipFileInfo64> getFileInfoList64() const;
/// Enables the zip64 mode.
/**
* @param zip64 If \c true, the zip64 mode is enabled, disabled otherwise.
*
* Once this is enabled, all new files (until the mode is disabled again)
* will be created in the zip64 mode, thus enabling the ability to write
* files larger than 4 GB. By default, the zip64 mode is off due to
* compatibility reasons.
*
* Note that this does not affect the ability to read zip64 archives in any
* way.
*
* \sa isZip64Enabled()
*/
void setZip64Enabled(bool zip64);
/// Returns whether the zip64 mode is enabled.
/**
* @return \c true if and only if the zip64 mode is enabled.
*
* \sa setZip64Enabled()
*/
bool isZip64Enabled() const;
+ /// Enables the use of UTF-8 encoding for file names and comments text.
+ /**
+ * @param utf8 If \c true, the UTF-8 mode is enabled, disabled otherwise.
+ *
+ * Once this is enabled, the names of all new files and comments text (until
+ * the mode is disabled again) will be encoded in UTF-8 encoding, and the
+ * version to extract will be set to 6.3 (63) in ZIP header. By default,
+ * the UTF-8 mode is off due to compatibility reasons.
+ *
+ * Note that when extracting ZIP archives, the UTF-8 mode is determined from
+ * ZIP file header, not from this flag.
+ *
+ * \sa isUtf8Enabled()
+ */
+ void setUtf8Enabled(bool utf8);
+ /// Returns whether the UTF-8 encoding mode is enabled.
+ /**
+ * @return \c true if and only if the UTF-8 mode is enabled.
+ *
+ * \sa setUtf8Enabled()
+ */
+ bool isUtf8Enabled() const;
/// Returns the auto-close flag.
/**
@sa setAutoClose()
*/
bool isAutoClose() const;
/// Sets or unsets the auto-close flag.
/**
By default, QuaZIP opens the underlying QIODevice when open() is called,
and closes it when close() is called. In some cases, when the device
is set explicitly using setIoDevice(), it may be desirable to
leave the device open. If the auto-close flag is unset using this method,
then the device isn't closed automatically if it was set explicitly.
If it is needed to clear this flag, it is recommended to do so before
opening the archive because otherwise QuaZIP may close the device
during the open() call if an error is encountered after the device
is opened.
If the device was not set explicitly, but rather the setZipName() or
the appropriate constructor was used to set the ZIP file name instead,
then the auto-close flag has no effect, and the internal device
is closed nevertheless because there is no other way to close it.
@sa isAutoClose()
@sa setIoDevice()
*/
void setAutoClose(bool autoClose) const;
/// Sets the default file name codec to use.
/**
* The default codec is used by the constructors, so calling this function
* won't affect the QuaZip instances already created at that moment.
*
* The codec specified here can be overriden by calling setFileNameCodec().
* If neither function is called, QTextCodec::codecForLocale() will be used
* to decode or encode file names. Use this function with caution if
* the application uses other libraries that depend on QuaZIP. Those
* libraries can either call this function by themselves, thus overriding
* your setting or can rely on the default encoding, thus failing
* mysteriously if you change it. For these reasons, it isn't recommended
* to use this function if you are developing a library, not an application.
* Instead, ask your library users to call it in case they need specific
* encoding.
*
* In most cases, using setFileNameCodec() instead is the right choice.
* However, if you depend on third-party code that uses QuaZIP, then the
* reasons stated above can actually become a reason to use this function
* in case the third-party code in question fails because it doesn't
* understand the encoding you need and doesn't provide a way to specify it.
* This applies to the JlCompress class as well, as it was contributed and
* doesn't support explicit encoding parameters.
*
* In short: use setFileNameCodec() when you can, resort to
* setDefaultFileNameCodec() when you don't have access to the QuaZip
* instance.
*
* @param codec The codec to use by default. If NULL, resets to default.
*/
static void setDefaultFileNameCodec(QTextCodec *codec);
/**
* @overload
* Equivalent to calling
- * setDefltFileNameCodec(QTextCodec::codecForName(codecName)).
+ * setDefaultFileNameCodec(QTextCodec::codecForName(codecName)).
*/
static void setDefaultFileNameCodec(const char *codecName);
+ /// Sets default OS code.
+ /**
+ * @sa setOsCode()
+ */
+ static void setDefaultOsCode(uint osCode);
+ /// Returns default OS code.
+ /**
+ * @sa getOsCode()
+ */
+ static uint getDefaultOsCode();
};
#endif
diff --git a/quazip/quazip.pro b/quazip/quazip.pro
--- a/quazip/quazip.pro
+++ b/quazip/quazip.pro
@@ -1,108 +1,113 @@
TEMPLATE = lib
CONFIG += qt warn_on
QT -= gui
# Creating pkgconfig .pc file
CONFIG += create_prl no_install_prl create_pc
QMAKE_PKGCONFIG_PREFIX = $$PREFIX
QMAKE_PKGCONFIG_INCDIR = $$headers.path
QMAKE_PKGCONFIG_REQUIRES = Qt5Core
# The ABI version.
!win32:VERSION = 1.0.0
# 1.0.0 is the first stable ABI.
# The next binary incompatible change will be 2.0.0 and so on.
# The existing QuaZIP policy on changing ABI requires to bump the
# major version of QuaZIP itself as well. Note that there may be
# other reasons for chaging the major version of QuaZIP, so
# in case where there is a QuaZIP major version bump but no ABI change,
# the VERSION variable will stay the same.
# For example:
# QuaZIP 1.0 is released after some 0.x, keeping binary compatibility.
# VERSION stays 1.0.0.
# Then some binary incompatible change is introduced. QuaZIP goes up to
# 2.0, VERSION to 2.0.0.
# And so on.
+greaterThan(QT_MAJOR_VERSION, 4) {
+ # disable all the Qt APIs deprecated before Qt 6.0.0
+ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000
+}
# This one handles dllimport/dllexport directives.
DEFINES += QUAZIP_BUILD
-
+DEFINES += QT_NO_CAST_FROM_ASCII
+DEFINES += QT_NO_CAST_TO_ASCII
# You'll need to define this one manually if using a build system other
# than qmake or using QuaZIP sources directly in your project.
CONFIG(staticlib): DEFINES += QUAZIP_STATIC
# Input
include(quazip.pri)
CONFIG(debug, debug|release) {
mac: TARGET = $$join(TARGET,,,_debug)
win32: TARGET = $$join(TARGET,,,d)
}
unix:!symbian {
headers.path=$$PREFIX/include/quazip
headers.files=$$HEADERS
target.path=$$PREFIX/lib/$${LIB_ARCH}
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
INSTALLS += headers target
OBJECTS_DIR=.obj
MOC_DIR=.moc
}
win32 {
headers.path=$$PREFIX/include/quazip
headers.files=$$HEADERS
INSTALLS += headers target
CONFIG(staticlib){
target.path=$$PREFIX/lib
QMAKE_PKGCONFIG_LIBDIR = $$PREFIX/lib/
} else {
target.path=$$PREFIX/bin
QMAKE_PKGCONFIG_LIBDIR = $$PREFIX/bin/
}
## odd, this path seems to be relative to the
## target.path, so if we install the .dll into
## the 'bin' dir, the .pc will go there as well,
## unless have hack the needed path...
## TODO any nicer solution?
QMAKE_PKGCONFIG_DESTDIR = ../lib/pkgconfig
# workaround for qdatetime.h macro bug
DEFINES += NOMINMAX
}
symbian {
# Note, on Symbian you may run into troubles with LGPL.
# The point is, if your application uses some version of QuaZip,
# and a newer binary compatible version of QuaZip is released, then
# the users of your application must be able to relink it with the
# new QuaZip version. For example, to take advantage of some QuaZip
# bug fixes.
# This is probably best achieved by building QuaZip as a static
# library and providing linkable object files of your application,
# so users can relink it.
CONFIG += staticlib
CONFIG += debug_and_release
LIBS += -lezip
#Export headers to SDK Epoc32/include directory
exportheaders.sources = $$HEADERS
exportheaders.path = quazip
for(header, exportheaders.sources) {
BLD_INF_RULES.prj_exports += "$$header $$exportheaders.path/$$basename(header)"
}
}
diff --git a/quazip/quazip_global.h b/quazip/quazip_global.h
--- a/quazip/quazip_global.h
+++ b/quazip/quazip_global.h
@@ -1,59 +1,63 @@
#ifndef QUAZIP_GLOBAL_H
#define QUAZIP_GLOBAL_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include <QtCore/qglobal.h>
/**
This is automatically defined when building a static library, but when
including QuaZip sources directly into a project, QUAZIP_STATIC should
be defined explicitly to avoid possible troubles with unnecessary
importing/exporting.
*/
#ifdef QUAZIP_STATIC
#define QUAZIP_EXPORT
#else
/**
* When building a DLL with MSVC, QUAZIP_BUILD must be defined.
* qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc.
*/
#if defined(QUAZIP_BUILD)
#define QUAZIP_EXPORT Q_DECL_EXPORT
#else
#define QUAZIP_EXPORT Q_DECL_IMPORT
#endif
#endif // QUAZIP_STATIC
#ifdef __GNUC__
#define QUAZIP_UNUSED __attribute__((__unused__))
#else
#define QUAZIP_UNUSED
#endif
#define QUAZIP_EXTRA_NTFS_MAGIC 0x000Au
#define QUAZIP_EXTRA_NTFS_TIME_MAGIC 0x0001u
+#define QUAZIP_EXTRA_EXT_TIME_MAGIC 0x5455u
+#define QUAZIP_EXTRA_EXT_MOD_TIME_FLAG 1
+#define QUAZIP_EXTRA_EXT_AC_TIME_FLAG 2
+#define QUAZIP_EXTRA_EXT_CR_TIME_FLAG 4
#endif // QUAZIP_GLOBAL_H
diff --git a/quazip/quazipfile.cpp b/quazip/quazipfile.cpp
--- a/quazip/quazipfile.cpp
+++ b/quazip/quazipfile.cpp
@@ -1,531 +1,570 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant, see
quazip/(un)zip.h files for details, basically it's zlib license.
**/
#include "quazipfile.h"
+#include "quazipfileinfo.h"
+
using namespace std;
+#define QUAZIP_VERSION_MADE_BY 0x1Eu
+
/// The implementation class for QuaZip.
/**
\internal
This class contains all the private stuff for the QuaZipFile class, thus
allowing to preserve binary compatibility between releases, the
technique known as the Pimpl (private implementation) idiom.
*/
class QuaZipFilePrivate {
friend class QuaZipFile;
private:
Q_DISABLE_COPY(QuaZipFilePrivate)
/// The pointer to the associated QuaZipFile instance.
QuaZipFile *q;
/// The QuaZip object to work with.
QuaZip *zip;
/// The file name.
QString fileName;
/// Case sensitivity mode.
QuaZip::CaseSensitivity caseSensitivity;
/// Whether this file is opened in the raw mode.
bool raw;
/// Write position to keep track of.
/**
QIODevice::pos() is broken for non-seekable devices, so we need
our own position.
*/
qint64 writePos;
/// Uncompressed size to write along with a raw file.
quint64 uncompressedSize;
/// CRC to write along with a raw file.
quint32 crc;
/// Whether \ref zip points to an internal QuaZip instance.
/**
This is true if the archive was opened by name, rather than by
supplying an existing QuaZip instance.
*/
bool internal;
/// The last error.
int zipError;
/// Resets \ref zipError.
inline void resetZipError() const {setZipError(UNZ_OK);}
/// Sets the zip error.
/**
This function is marked as const although it changes one field.
This allows to call it from const functions that don't change
anything by themselves.
*/
void setZipError(int zipError) const;
/// The constructor for the corresponding QuaZipFile constructor.
inline QuaZipFilePrivate(QuaZipFile *q):
q(q),
zip(NULL),
caseSensitivity(QuaZip::csDefault),
raw(false),
writePos(0),
uncompressedSize(0),
crc(0),
internal(true),
zipError(UNZ_OK) {}
/// The constructor for the corresponding QuaZipFile constructor.
inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
q(q),
caseSensitivity(QuaZip::csDefault),
raw(false),
writePos(0),
uncompressedSize(0),
crc(0),
internal(true),
zipError(UNZ_OK)
{
zip=new QuaZip(zipName);
}
/// The constructor for the corresponding QuaZipFile constructor.
inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
QuaZip::CaseSensitivity cs):
q(q),
raw(false),
writePos(0),
uncompressedSize(0),
crc(0),
internal(true),
zipError(UNZ_OK)
{
zip=new QuaZip(zipName);
this->fileName=fileName;
- if (this->fileName.startsWith('/'))
+ if (this->fileName.startsWith(QLatin1String("/")))
this->fileName = this->fileName.mid(1);
this->caseSensitivity=cs;
}
/// The constructor for the QuaZipFile constructor accepting a file name.
inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
q(q),
zip(zip),
raw(false),
writePos(0),
uncompressedSize(0),
crc(0),
internal(false),
zipError(UNZ_OK) {}
/// The destructor.
inline ~QuaZipFilePrivate()
{
if (internal)
delete zip;
}
};
QuaZipFile::QuaZipFile():
p(new QuaZipFilePrivate(this))
{
}
QuaZipFile::QuaZipFile(QObject *parent):
QIODevice(parent),
p(new QuaZipFilePrivate(this))
{
}
QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
QIODevice(parent),
p(new QuaZipFilePrivate(this, zipName))
{
}
QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
QuaZip::CaseSensitivity cs, QObject *parent):
QIODevice(parent),
p(new QuaZipFilePrivate(this, zipName, fileName, cs))
{
}
QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
QIODevice(parent),
p(new QuaZipFilePrivate(this, zip))
{
}
QuaZipFile::~QuaZipFile()
{
if (isOpen())
close();
delete p;
}
QString QuaZipFile::getZipName() const
{
return p->zip==NULL ? QString() : p->zip->getZipName();
}
QuaZip *QuaZipFile::getZip() const
{
return p->internal ? NULL : p->zip;
}
QString QuaZipFile::getActualFileName()const
{
p->setZipError(UNZ_OK);
if (p->zip == NULL || (openMode() & WriteOnly))
return QString();
QString name=p->zip->getCurrentFileName();
if(name.isNull())
p->setZipError(p->zip->getZipError());
return name;
}
void QuaZipFile::setZipName(const QString& zipName)
{
if(isOpen()) {
qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
return;
}
if(p->zip!=NULL && p->internal)
delete p->zip;
p->zip=new QuaZip(zipName);
p->internal=true;
}
void QuaZipFile::setZip(QuaZip *zip)
{
if(isOpen()) {
qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
return;
}
if(p->zip!=NULL && p->internal)
delete p->zip;
p->zip=zip;
p->fileName=QString();
p->internal=false;
}
void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
{
if(p->zip==NULL) {
qWarning("QuaZipFile::setFileName(): call setZipName() first");
return;
}
if(!p->internal) {
qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
return;
}
if(isOpen()) {
qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
return;
}
p->fileName=fileName;
- if (p->fileName.startsWith('/'))
+ if (p->fileName.startsWith(QLatin1String("/")))
p->fileName = p->fileName.mid(1);
p->caseSensitivity=cs;
}
void QuaZipFilePrivate::setZipError(int zipError) const
{
QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
fakeThis->zipError=zipError;
if(zipError==UNZ_OK)
q->setErrorString(QString());
else
q->setErrorString(QuaZipFile::tr("ZIP/UNZIP API error %1").arg(zipError));
}
bool QuaZipFile::open(OpenMode mode)
{
return open(mode, NULL);
}
bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
{
p->resetZipError();
if(isOpen()) {
qWarning("QuaZipFile::open(): already opened");
return false;
}
if(mode&Unbuffered) {
qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
return false;
}
if((mode&ReadOnly)&&!(mode&WriteOnly)) {
if(p->internal) {
if(!p->zip->open(QuaZip::mdUnzip)) {
p->setZipError(p->zip->getZipError());
return false;
}
if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
p->setZipError(p->zip->getZipError());
p->zip->close();
return false;
}
} else {
if(p->zip==NULL) {
qWarning("QuaZipFile::open(): zip is NULL");
return false;
}
if(p->zip->getMode()!=QuaZip::mdUnzip) {
qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
(int)mode, (int)p->zip->getMode());
return false;
}
if(!p->zip->hasCurrentFile()) {
qWarning("QuaZipFile::open(): zip does not have current file");
return false;
}
}
p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
if(p->zipError==UNZ_OK) {
setOpenMode(mode);
p->raw=raw;
return true;
} else
return false;
}
qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
return false;
}
bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
const char *password, quint32 crc,
int method, int level, bool raw,
int windowBits, int memLevel, int strategy)
{
zip_fileinfo info_z;
p->resetZipError();
if(isOpen()) {
qWarning("QuaZipFile::open(): already opened");
return false;
}
if((mode&WriteOnly)&&!(mode&ReadOnly)) {
if(p->internal) {
qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
return false;
}
if(p->zip==NULL) {
qWarning("QuaZipFile::open(): zip is NULL");
return false;
}
if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
(int)mode, (int)p->zip->getMode());
return false;
}
info_z.tmz_date.tm_year=info.dateTime.date().year();
info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
info_z.tmz_date.tm_mday=info.dateTime.date().day();
info_z.tmz_date.tm_hour=info.dateTime.time().hour();
info_z.tmz_date.tm_min=info.dateTime.time().minute();
info_z.tmz_date.tm_sec=info.dateTime.time().second();
info_z.dosDate = 0;
info_z.internal_fa=(uLong)info.internalAttr;
info_z.external_fa=(uLong)info.externalAttr;
if (p->zip->isDataDescriptorWritingEnabled())
zipSetFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
else
zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
- p->setZipError(zipOpenNewFileInZip3_64(p->zip->getZipFile(),
- p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
+ p->setZipError(zipOpenNewFileInZip4_64(p->zip->getZipFile(),
+ p->zip->isUtf8Enabled()
+ ? info.name.toUtf8().constData()
+ : p->zip->getFileNameCodec()->fromUnicode(info.name).constData(),
+ &info_z,
info.extraLocal.constData(), info.extraLocal.length(),
info.extraGlobal.constData(), info.extraGlobal.length(),
- p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
+ p->zip->isUtf8Enabled()
+ ? info.comment.toUtf8().constData()
+ : p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
method, level, (int)raw,
windowBits, memLevel, strategy,
- password, (uLong)crc, p->zip->isZip64Enabled()));
+ password, (uLong)crc,
+ (p->zip->getOsCode() << 8) | QUAZIP_VERSION_MADE_BY,
+ 0,
+ p->zip->isZip64Enabled()));
if(p->zipError==UNZ_OK) {
p->writePos=0;
setOpenMode(mode);
p->raw=raw;
if(raw) {
p->crc=crc;
p->uncompressedSize=info.uncompressedSize;
}
return true;
} else
return false;
}
qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
return false;
}
bool QuaZipFile::isSequential()const
{
return true;
}
qint64 QuaZipFile::pos()const
{
if(p->zip==NULL) {
qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
return -1;
}
if(!isOpen()) {
qWarning("QuaZipFile::pos(): file is not open");
return -1;
}
if(openMode()&ReadOnly)
// QIODevice::pos() is broken for sequential devices,
// but thankfully bytesAvailable() returns the number of
// bytes buffered, so we know how far ahead we are.
return unztell64(p->zip->getUnzFile()) - QIODevice::bytesAvailable();
else
return p->writePos;
}
bool QuaZipFile::atEnd()const
{
if(p->zip==NULL) {
qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
return false;
}
if(!isOpen()) {
qWarning("QuaZipFile::atEnd(): file is not open");
return false;
}
if(openMode()&ReadOnly)
// the same problem as with pos()
return QIODevice::bytesAvailable() == 0
&& unzeof(p->zip->getUnzFile())==1;
else
return true;
}
qint64 QuaZipFile::size()const
{
if(!isOpen()) {
qWarning("QuaZipFile::atEnd(): file is not open");
return -1;
}
if(openMode()&ReadOnly)
return p->raw?csize():usize();
else
return p->writePos;
}
qint64 QuaZipFile::csize()const
{
unz_file_info64 info_z;
p->setZipError(UNZ_OK);
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
if(p->zipError!=UNZ_OK)
return -1;
return info_z.compressed_size;
}
qint64 QuaZipFile::usize()const
{
unz_file_info64 info_z;
p->setZipError(UNZ_OK);
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
p->setZipError(unzGetCurrentFileInfo64(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
if(p->zipError!=UNZ_OK)
return -1;
return info_z.uncompressed_size;
}
bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
{
QuaZipFileInfo64 info64;
if (getFileInfo(&info64)) {
info64.toQuaZipFileInfo(*info);
return true;
} else {
return false;
}
}
bool QuaZipFile::getFileInfo(QuaZipFileInfo64 *info)
{
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
p->zip->getCurrentFileInfo(info);
p->setZipError(p->zip->getZipError());
return p->zipError==UNZ_OK;
}
void QuaZipFile::close()
{
p->resetZipError();
if(p->zip==NULL||!p->zip->isOpen()) return;
if(!isOpen()) {
qWarning("QuaZipFile::close(): file isn't open");
return;
}
if(openMode()&ReadOnly)
p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
else if(openMode()&WriteOnly)
if(isRaw()) p->setZipError(zipCloseFileInZipRaw64(p->zip->getZipFile(), p->uncompressedSize, p->crc));
else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
else {
qWarning("Wrong open mode: %d", (int)openMode());
return;
}
if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
else return;
if(p->internal) {
p->zip->close();
p->setZipError(p->zip->getZipError());
}
}
qint64 QuaZipFile::readData(char *data, qint64 maxSize)
{
p->setZipError(UNZ_OK);
qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
if (bytesRead < 0) {
p->setZipError((int) bytesRead);
return -1;
}
return bytesRead;
}
qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
{
p->setZipError(ZIP_OK);
p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
if(p->zipError!=ZIP_OK) return -1;
else {
p->writePos+=maxSize;
return maxSize;
}
}
QString QuaZipFile::getFileName() const
{
return p->fileName;
}
QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
{
return p->caseSensitivity;
}
bool QuaZipFile::isRaw() const
{
return p->raw;
}
int QuaZipFile::getZipError() const
{
return p->zipError;
}
qint64 QuaZipFile::bytesAvailable() const
{
return size() - pos();
}
+
+QByteArray QuaZipFile::getLocalExtraField()
+{
+ int size = unzGetLocalExtrafield(p->zip->getUnzFile(), NULL, 0);
+ QByteArray extra(size, '\0');
+ int err = unzGetLocalExtrafield(p->zip->getUnzFile(), extra.data(), static_cast<uint>(extra.size()));
+ if (err < 0) {
+ p->setZipError(err);
+ return QByteArray();
+ }
+ return extra;
+}
+
+QDateTime QuaZipFile::getExtModTime()
+{
+ return QuaZipFileInfo64::getExtTime(getLocalExtraField(), QUAZIP_EXTRA_EXT_MOD_TIME_FLAG);
+}
+
+QDateTime QuaZipFile::getExtAcTime()
+{
+ return QuaZipFileInfo64::getExtTime(getLocalExtraField(), QUAZIP_EXTRA_EXT_AC_TIME_FLAG);
+}
+
+QDateTime QuaZipFile::getExtCrTime()
+{
+ return QuaZipFileInfo64::getExtTime(getLocalExtraField(), QUAZIP_EXTRA_EXT_CR_TIME_FLAG);
+}
diff --git a/quazip/quazipfile.h b/quazip/quazipfile.h
--- a/quazip/quazipfile.h
+++ b/quazip/quazipfile.h
@@ -1,456 +1,508 @@
#ifndef QUA_ZIPFILE_H
#define QUA_ZIPFILE_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant, see
quazip/(un)zip.h files for details, basically it's zlib license.
**/
-#include <QIODevice>
+#include <QtCore/QIODevice>
#include "quazip_global.h"
#include "quazip.h"
#include "quazipnewinfo.h"
class QuaZipFilePrivate;
/// A file inside ZIP archive.
/** \class QuaZipFile quazipfile.h <quazip/quazipfile.h>
* This is the most interesting class. Not only it provides C++
* interface to the ZIP/UNZIP package, but also integrates it with Qt by
* subclassing QIODevice. This makes possible to access files inside ZIP
* archive using QTextStream or QDataStream, for example. Actually, this
* is the main purpose of the whole QuaZIP library.
*
* You can either use existing QuaZip instance to create instance of
* this class or pass ZIP archive file name to this class, in which case
* it will create internal QuaZip object. See constructors' descriptions
* for details. Writing is only possible with the existing instance.
*
* Note that due to the underlying library's limitation it is not
* possible to use multiple QuaZipFile instances to open several files
* in the same archive at the same time. If you need to write to
* multiple files in parallel, then you should write to temporary files
* first, then pack them all at once when you have finished writing. If
* you need to read multiple files inside the same archive in parallel,
* you should extract them all into a temporary directory first.
*
* \section quazipfile-sequential Sequential or random-access?
*
* At the first thought, QuaZipFile has fixed size, the start and the
* end and should be therefore considered random-access device. But
* there is one major obstacle to making it random-access: ZIP/UNZIP API
* does not support seek() operation and the only way to implement it is
* through reopening the file and re-reading to the required position,
* but this is prohibitively slow.
*
* Therefore, QuaZipFile is considered to be a sequential device. This
* has advantage of availability of the ungetChar() operation (QIODevice
* does not implement it properly for non-sequential devices unless they
* support seek()). Disadvantage is a somewhat strange behaviour of the
* size() and pos() functions. This should be kept in mind while using
* this class.
*
**/
class QUAZIP_EXPORT QuaZipFile: public QIODevice {
friend class QuaZipFilePrivate;
Q_OBJECT
private:
QuaZipFilePrivate *p;
// these are not supported nor implemented
QuaZipFile(const QuaZipFile& that);
QuaZipFile& operator=(const QuaZipFile& that);
protected:
/// Implementation of the QIODevice::readData().
qint64 readData(char *data, qint64 maxSize);
/// Implementation of the QIODevice::writeData().
qint64 writeData(const char *data, qint64 maxSize);
public:
/// Constructs a QuaZipFile instance.
/** You should use setZipName() and setFileName() or setZip() before
* trying to call open() on the constructed object.
**/
QuaZipFile();
/// Constructs a QuaZipFile instance.
/** \a parent argument specifies this object's parent object.
*
* You should use setZipName() and setFileName() or setZip() before
* trying to call open() on the constructed object.
**/
QuaZipFile(QObject *parent);
/// Constructs a QuaZipFile instance.
/** \a parent argument specifies this object's parent object and \a
* zipName specifies ZIP archive file name.
*
* You should use setFileName() before trying to call open() on the
* constructed object.
*
* QuaZipFile constructed by this constructor can be used for read
* only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
**/
QuaZipFile(const QString& zipName, QObject *parent =NULL);
/// Constructs a QuaZipFile instance.
/** \a parent argument specifies this object's parent object, \a
* zipName specifies ZIP archive file name and \a fileName and \a cs
* specify a name of the file to open inside archive.
*
* QuaZipFile constructed by this constructor can be used for read
* only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
*
* \sa QuaZip::setCurrentFile()
**/
QuaZipFile(const QString& zipName, const QString& fileName,
QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL);
/// Constructs a QuaZipFile instance.
/** \a parent argument specifies this object's parent object.
*
* \a zip is the pointer to the existing QuaZip object. This
* QuaZipFile object then can be used to read current file in the
* \a zip or to write to the file inside it.
*
* \warning Using this constructor for reading current file can be
* tricky. Let's take the following example:
* \code
* QuaZip zip("archive.zip");
* zip.open(QuaZip::mdUnzip);
* zip.setCurrentFile("file-in-archive");
* QuaZipFile file(&zip);
* file.open(QIODevice::ReadOnly);
* // ok, now we can read from the file
* file.read(somewhere, some);
* zip.setCurrentFile("another-file-in-archive"); // oops...
* QuaZipFile anotherFile(&zip);
* anotherFile.open(QIODevice::ReadOnly);
* anotherFile.read(somewhere, some); // this is still ok...
* file.read(somewhere, some); // and this is NOT
* \endcode
* So, what exactly happens here? When we change current file in the
* \c zip archive, \c file that references it becomes invalid
* (actually, as far as I understand ZIP/UNZIP sources, it becomes
* closed, but QuaZipFile has no means to detect it).
*
* Summary: do not close \c zip object or change its current file as
* long as QuaZipFile is open. Even better - use another constructors
* which create internal QuaZip instances, one per object, and
* therefore do not cause unnecessary trouble. This constructor may
* be useful, though, if you already have a QuaZip instance and do
* not want to access several files at once. Good example:
* \code
* QuaZip zip("archive.zip");
* zip.open(QuaZip::mdUnzip);
* // first, we need some information about archive itself
* QByteArray comment=zip.getComment();
* // and now we are going to access files inside it
* QuaZipFile file(&zip);
* for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
* file.open(QIODevice::ReadOnly);
* // do something cool with file here
* file.close(); // do not forget to close!
* }
* zip.close();
* \endcode
**/
QuaZipFile(QuaZip *zip, QObject *parent =NULL);
/// Destroys a QuaZipFile instance.
/** Closes file if open, destructs internal QuaZip object (if it
* exists and \em is internal, of course).
**/
virtual ~QuaZipFile();
/// Returns the ZIP archive file name.
/** If this object was created by passing QuaZip pointer to the
* constructor, this function will return that QuaZip's file name
* (or null string if that object does not have file name yet).
*
* Otherwise, returns associated ZIP archive file name or null
* string if there are no name set yet.
*
* \sa setZipName() getFileName()
**/
QString getZipName()const;
/// Returns a pointer to the associated QuaZip object.
/** Returns \c NULL if there is no associated QuaZip or it is
* internal (so you will not mess with it).
**/
QuaZip* getZip()const;
/// Returns file name.
/** This function returns file name you passed to this object either
* by using
* QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
* or by calling setFileName(). Real name of the file may differ in
* case if you used case-insensitivity.
*
* Returns null string if there is no file name set yet. This is the
* case when this QuaZipFile operates on the existing QuaZip object
* (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used).
*
* \sa getActualFileName
**/
QString getFileName() const;
/// Returns case sensitivity of the file name.
/** This function returns case sensitivity argument you passed to
* this object either by using
* QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
* or by calling setFileName().
*
* Returns unpredictable value if getFileName() returns null string
* (this is the case when you did not used setFileName() or
* constructor above).
*
* \sa getFileName
**/
QuaZip::CaseSensitivity getCaseSensitivity() const;
/// Returns the actual file name in the archive.
/** This is \em not a ZIP archive file name, but a name of file inside
* archive. It is not necessary the same name that you have passed
* to the
* QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*),
* setFileName() or QuaZip::setCurrentFile() - this is the real file
* name inside archive, so it may differ in case if the file name
* search was case-insensitive.
*
* Equivalent to calling getCurrentFileName() on the associated
* QuaZip object. Returns null string if there is no associated
* QuaZip object or if it does not have a current file yet. And this
* is the case if you called setFileName() but did not open the
* file yet. So this is perfectly fine:
* \code
* QuaZipFile file("somezip.zip");
* file.setFileName("somefile");
* QString name=file.getName(); // name=="somefile"
* QString actual=file.getActualFileName(); // actual is null string
* file.open(QIODevice::ReadOnly);
* QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows
* \endcode
*
* \sa getZipName(), getFileName(), QuaZip::CaseSensitivity
**/
QString getActualFileName()const;
/// Sets the ZIP archive file name.
/** Automatically creates internal QuaZip object and destroys
* previously created internal QuaZip object, if any.
*
* Will do nothing if this file is already open. You must close() it
* first.
**/
void setZipName(const QString& zipName);
/// Returns \c true if the file was opened in raw mode.
/** If the file is not open, the returned value is undefined.
*
* \sa open(OpenMode,int*,int*,bool,const char*)
**/
bool isRaw() const;
/// Binds to the existing QuaZip instance.
/** This function destroys internal QuaZip object, if any, and makes
* this QuaZipFile to use current file in the \a zip object for any
* further operations. See QuaZipFile(QuaZip*,QObject*) for the
* possible pitfalls.
*
* Will do nothing if the file is currently open. You must close()
* it first.
**/
void setZip(QuaZip *zip);
/// Sets the file name.
/** Will do nothing if at least one of the following conditions is
* met:
* - ZIP name has not been set yet (getZipName() returns null
* string).
* - This QuaZipFile is associated with external QuaZip. In this
* case you should call that QuaZip's setCurrentFile() function
* instead!
* - File is already open so setting the name is meaningless.
*
* \sa QuaZip::setCurrentFile
**/
void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault);
/// Opens a file for reading.
/** Returns \c true on success, \c false otherwise.
* Call getZipError() to get error code.
*
* \note Since ZIP/UNZIP API provides buffered reading only,
* QuaZipFile does not support unbuffered reading. So do not pass
* QIODevice::Unbuffered flag in \a mode, or open will fail.
**/
virtual bool open(OpenMode mode);
/// Opens a file for reading.
/** \overload
* Argument \a password specifies a password to decrypt the file. If
* it is NULL then this function behaves just like open(OpenMode).
**/
inline bool open(OpenMode mode, const char *password)
{return open(mode, NULL, NULL, false, password);}
/// Opens a file for reading.
/** \overload
* Argument \a password specifies a password to decrypt the file.
*
* An integers pointed by \a method and \a level will receive codes
* of the compression method and level used. See unzip.h.
*
* If raw is \c true then no decompression is performed.
*
* \a method should not be \c NULL. \a level can be \c NULL if you
* don't want to know the compression level.
**/
bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL);
/// Opens a file for writing.
/** \a info argument specifies information about file. It should at
* least specify a correct file name. Also, it is a good idea to
* specify correct timestamp (by default, current time will be
* used). See QuaZipNewInfo.
*
* The \a password argument specifies the password for crypting. Pass NULL
* if you don't need any crypting. The \a crc argument was supposed
* to be used for crypting too, but then it turned out that it's
* false information, so you need to set it to 0 unless you want to
* use the raw mode (see below).
*
* Arguments \a method and \a level specify compression method and
* level. The only method supported is Z_DEFLATED, but you may also
* specify 0 for no compression. If all of the files in the archive
* use both method 0 and either level 0 is explicitly specified or
* data descriptor writing is disabled with
* QuaZip::setDataDescriptorWritingEnabled(), then the
* resulting archive is supposed to be compatible with the 1.0 ZIP
* format version, should you need that. Except for this, \a level
* has no other effects with method 0.
*
* If \a raw is \c true, no compression is performed. In this case,
* \a crc and uncompressedSize field of the \a info are required.
*
* Arguments \a windowBits, \a memLevel, \a strategy provide zlib
* algorithms tuning. See deflateInit2() in zlib.
**/
bool open(OpenMode mode, const QuaZipNewInfo& info,
const char *password =NULL, quint32 crc =0,
int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false,
int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY);
/// Returns \c true, but \ref quazipfile-sequential "beware"!
virtual bool isSequential()const;
/// Returns current position in the file.
/** Implementation of the QIODevice::pos(). When reading, this
* function is a wrapper to the ZIP/UNZIP unztell(), therefore it is
* unable to keep track of the ungetChar() calls (which is
* non-virtual and therefore is dangerous to reimplement). So if you
* are using ungetChar() feature of the QIODevice, this function
* reports incorrect value until you get back characters which you
* ungot.
*
* When writing, pos() returns number of bytes already written
* (uncompressed unless you use raw mode).
*
* \note Although
* \ref quazipfile-sequential "QuaZipFile is a sequential device"
* and therefore pos() should always return zero, it does not,
* because it would be misguiding. Keep this in mind.
*
* This function returns -1 if the file or archive is not open.
*
* Error code returned by getZipError() is not affected by this
* function call.
**/
virtual qint64 pos()const;
/// Returns \c true if the end of file was reached.
/** This function returns \c false in the case of error. This means
* that you called this function on either not open file, or a file
* in the not open archive or even on a QuaZipFile instance that
* does not even have QuaZip instance associated. Do not do that
* because there is no means to determine whether \c false is
* returned because of error or because end of file was reached.
* Well, on the other side you may interpret \c false return value
* as "there is no file open to check for end of file and there is
* no end of file therefore".
*
* When writing, this function always returns \c true (because you
* are always writing to the end of file).
*
* Error code returned by getZipError() is not affected by this
* function call.
**/
virtual bool atEnd()const;
/// Returns file size.
/** This function returns csize() if the file is open for reading in
* raw mode, usize() if it is open for reading in normal mode and
* pos() if it is open for writing.
*
* Returns -1 on error, call getZipError() to get error code.
*
* \note This function returns file size despite that
* \ref quazipfile-sequential "QuaZipFile is considered to be sequential device",
* for which size() should return bytesAvailable() instead. But its
* name would be very misguiding otherwise, so just keep in mind
* this inconsistence.
**/
virtual qint64 size()const;
/// Returns compressed file size.
/** Equivalent to calling getFileInfo() and then getting
* compressedSize field, but more convenient and faster.
*
* File must be open for reading before calling this function.
*
* Returns -1 on error, call getZipError() to get error code.
**/
qint64 csize()const;
/// Returns uncompressed file size.
/** Equivalent to calling getFileInfo() and then getting
* uncompressedSize field, but more convenient and faster. See
* getFileInfo() for a warning.
*
* File must be open for reading before calling this function.
*
* Returns -1 on error, call getZipError() to get error code.
**/
qint64 usize()const;
/// Gets information about current file.
/** This function does the same thing as calling
* QuaZip::getCurrentFileInfo() on the associated QuaZip object,
* but you can not call getCurrentFileInfo() if the associated
* QuaZip is internal (because you do not have access to it), while
* you still can call this function in that case.
*
* File must be open for reading before calling this function.
*
* \return \c false in the case of an error.
*
* This function doesn't support zip64, but will still work fine on zip64
* archives if file sizes are below 4 GB, otherwise the values will be set
* as if converted using QuaZipFileInfo64::toQuaZipFileInfo().
*
* \sa getFileInfo(QuaZipFileInfo64*)
**/
bool getFileInfo(QuaZipFileInfo *info);
/// Gets information about current file with zip64 support.
/**
* @overload
*
* \sa getFileInfo(QuaZipFileInfo*)
*/
bool getFileInfo(QuaZipFileInfo64 *info);
/// Closes the file.
/** Call getZipError() to determine if the close was successful.
**/
virtual void close();
/// Returns the error code returned by the last ZIP/UNZIP API call.
int getZipError() const;
/// Returns the number of bytes available for reading.
virtual qint64 bytesAvailable() const;
+ /// Returns the local extra field
+ /**
+ There are two (optional) local extra fields associated with a file.
+ One is located in the central header and is available along
+ with the rest of the file information in @ref QuaZipFileInfo64::extra.
+ Another is located before the file itself,
+ and is returned by this function. The file must be open first.
+
+ @return the local extra field, or an empty array if there is none
+ (or file is not open)
+ */
+ QByteArray getLocalExtraField();
+ /// Returns the extended modification timestamp
+ /**
+ * The getExt*Time() functions only work if there is an extended timestamp
+ * extra field (ID 0x5455) present. Otherwise, they all return invalid null
+ * timestamps.
+ *
+ * Modification time, but not other times, can also be accessed through
+ * @ref QuaZipFileInfo64 without the need to open the file first.
+ *
+ * @sa dateTime
+ * @sa QuaZipFileInfo64::getExtModTime()
+ * @sa getExtAcTime()
+ * @sa getExtCrTime()
+ * @return The extended modification time, UTC
+ */
+ QDateTime getExtModTime();
+ /// Returns the extended access timestamp
+ /**
+ * The getExt*Time() functions only work if there is an extended timestamp
+ * extra field (ID 0x5455) present. Otherwise, they all return invalid null
+ * timestamps.
+ * @sa dateTime
+ * @sa QuaZipFileInfo64::getExtModTime()
+ * @sa getExtModTime()
+ * @sa getExtCrTime()
+ * @return The extended access time, UTC
+ */
+ QDateTime getExtAcTime();
+ /// Returns the extended creation timestamp
+ /**
+ * The getExt*Time() functions only work if there is an extended timestamp
+ * extra field (ID 0x5455) present. Otherwise, they all return invalid null
+ * timestamps.
+ * @sa dateTime
+ * @sa QuaZipFileInfo64::getExtModTime()
+ * @sa getExtModTime()
+ * @sa getExtAcTime()
+ * @return The extended creation time, UTC
+ */
+ QDateTime getExtCrTime();
};
#endif
diff --git a/quazip/quazipfileinfo.cpp b/quazip/quazipfileinfo.cpp
--- a/quazip/quazipfileinfo.cpp
+++ b/quazip/quazipfileinfo.cpp
@@ -1,176 +1,196 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "quazipfileinfo.h"
+#include <QtCore/QDataStream>
+
static QFile::Permissions permissionsFromExternalAttr(quint32 externalAttr) {
quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16;
- QFile::Permissions perm = 0;
+ QFile::Permissions perm {};
if ((uPerm & 0400) != 0)
perm |= QFile::ReadOwner;
if ((uPerm & 0200) != 0)
perm |= QFile::WriteOwner;
if ((uPerm & 0100) != 0)
perm |= QFile::ExeOwner;
if ((uPerm & 0040) != 0)
perm |= QFile::ReadGroup;
if ((uPerm & 0020) != 0)
perm |= QFile::WriteGroup;
if ((uPerm & 0010) != 0)
perm |= QFile::ExeGroup;
if ((uPerm & 0004) != 0)
perm |= QFile::ReadOther;
if ((uPerm & 0002) != 0)
perm |= QFile::WriteOther;
if ((uPerm & 0001) != 0)
perm |= QFile::ExeOther;
return perm;
}
QFile::Permissions QuaZipFileInfo::getPermissions() const
{
return permissionsFromExternalAttr(externalAttr);
}
QFile::Permissions QuaZipFileInfo64::getPermissions() const
{
return permissionsFromExternalAttr(externalAttr);
}
bool QuaZipFileInfo64::toQuaZipFileInfo(QuaZipFileInfo &info) const
{
bool noOverflow = true;
info.name = name;
info.versionCreated = versionCreated;
info.versionNeeded = versionNeeded;
info.flags = flags;
info.method = method;
info.dateTime = dateTime;
info.crc = crc;
if (compressedSize > 0xFFFFFFFFu) {
info.compressedSize = 0xFFFFFFFFu;
noOverflow = false;
} else {
info.compressedSize = compressedSize;
}
if (uncompressedSize > 0xFFFFFFFFu) {
info.uncompressedSize = 0xFFFFFFFFu;
noOverflow = false;
} else {
info.uncompressedSize = uncompressedSize;
}
info.diskNumberStart = diskNumberStart;
info.internalAttr = internalAttr;
info.externalAttr = externalAttr;
info.comment = comment;
info.extra = extra;
return noOverflow;
}
static QDateTime getNTFSTime(const QByteArray &extra, int position,
int *fineTicks)
{
QDateTime dateTime;
- for (int i = 0; i <= extra.size() - 4; ) {
- unsigned type = static_cast<unsigned>(static_cast<unsigned char>(
- extra.at(i)))
- | (static_cast<unsigned>(static_cast<unsigned char>(
- extra.at(i + 1))) << 8);
- i += 2;
- unsigned length = static_cast<unsigned>(static_cast<unsigned char>(
- extra.at(i)))
- | (static_cast<unsigned>(static_cast<unsigned char>(
- extra.at(i + 1))) << 8);
- i += 2;
- if (type == QUAZIP_EXTRA_NTFS_MAGIC && length >= 32) {
- i += 4; // reserved
- while (i <= extra.size() - 4) {
- unsigned tag = static_cast<unsigned>(
- static_cast<unsigned char>(extra.at(i)))
- | (static_cast<unsigned>(
- static_cast<unsigned char>(extra.at(i + 1)))
- << 8);
- i += 2;
- int tagsize = static_cast<unsigned>(
- static_cast<unsigned char>(extra.at(i)))
- | (static_cast<unsigned>(
- static_cast<unsigned char>(extra.at(i + 1)))
- << 8);
- i += 2;
- if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC
- && tagsize >= position + 8) {
- i += position;
- quint64 mtime = static_cast<quint64>(
- static_cast<unsigned char>(extra.at(i)))
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 1))) << 8)
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 2))) << 16)
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 3))) << 24)
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 4))) << 32)
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 5))) << 40)
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 6))) << 48)
- | (static_cast<quint64>(static_cast<unsigned char>(
- extra.at(i + 7))) << 56);
- // the NTFS time is measured from 1601 for whatever reason
- QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
- dateTime = base.addMSecs(mtime / 10000);
- if (fineTicks != NULL) {
- *fineTicks = static_cast<int>(mtime % 10000);
- }
- i += tagsize - position;
- } else {
- i += tagsize;
- }
-
- }
- } else {
- i += length;
- }
- }
- if (fineTicks != NULL && dateTime.isNull()) {
- *fineTicks = 0;
+ QuaExtraFieldHash extraHash = QuaZipFileInfo64::parseExtraField(extra);
+ QList<QByteArray> ntfsExtraFields = extraHash[QUAZIP_EXTRA_NTFS_MAGIC];
+ if (ntfsExtraFields.isEmpty())
+ return dateTime;
+ QByteArray ntfsExtraField = ntfsExtraFields.at(0);
+ if (ntfsExtraField.length() <= 4)
+ return dateTime;
+ QByteArray ntfsAttributes = ntfsExtraField.mid(4);
+ QuaExtraFieldHash ntfsHash = QuaZipFileInfo64::parseExtraField(ntfsAttributes);
+ QList<QByteArray> ntfsTimeAttributes = ntfsHash[QUAZIP_EXTRA_NTFS_TIME_MAGIC];
+ if (ntfsTimeAttributes.isEmpty())
+ return dateTime;
+ QByteArray ntfsTimes = ntfsTimeAttributes.at(0);
+ if (ntfsTimes.size() < 24)
+ return dateTime;
+ QDataStream timeReader(ntfsTimes);
+ timeReader.setByteOrder(QDataStream::LittleEndian);
+ timeReader.device()->seek(position);
+ quint64 time;
+ timeReader >> time;
+ QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
+ dateTime = base.addMSecs(time / 10000);
+ if (fineTicks != NULL) {
+ *fineTicks = static_cast<int>(time % 10000);
}
return dateTime;
}
QDateTime QuaZipFileInfo64::getNTFSmTime(int *fineTicks) const
{
return getNTFSTime(extra, 0, fineTicks);
}
QDateTime QuaZipFileInfo64::getNTFSaTime(int *fineTicks) const
{
return getNTFSTime(extra, 8, fineTicks);
}
QDateTime QuaZipFileInfo64::getNTFScTime(int *fineTicks) const
{
return getNTFSTime(extra, 16, fineTicks);
}
+
+QDateTime QuaZipFileInfo64::getExtTime(const QByteArray &extra, int flag)
+{
+ QDateTime dateTime;
+ QuaExtraFieldHash extraHash = QuaZipFileInfo64::parseExtraField(extra);
+ QList<QByteArray> extTimeFields = extraHash[QUAZIP_EXTRA_EXT_TIME_MAGIC];
+ if (extTimeFields.isEmpty())
+ return dateTime;
+ QByteArray extTimeField = extTimeFields.at(0);
+ if (extTimeField.length() < 1)
+ return dateTime;
+ QDataStream input(extTimeField);
+ input.setByteOrder(QDataStream::LittleEndian);
+ quint8 flags;
+ input >> flags;
+ int flagsRemaining = flags;
+ while (!input.atEnd()) {
+ int nextFlag = flagsRemaining & -flagsRemaining;
+ flagsRemaining &= flagsRemaining - 1;
+ qint32 time;
+ input >> time;
+ if (nextFlag == flag) {
+ QDateTime base(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC);
+ dateTime = base.addSecs(time);
+ return dateTime;
+ }
+ }
+ return dateTime;
+}
+
+QDateTime QuaZipFileInfo64::getExtModTime() const
+{
+ return getExtTime(extra, 1);
+}
+
+QuaExtraFieldHash QuaZipFileInfo64::parseExtraField(const QByteArray &extraField)
+{
+ QDataStream input(extraField);
+ input.setByteOrder(QDataStream::LittleEndian);
+ QHash<quint16, QList<QByteArray> > result;
+ while (!input.atEnd()) {
+ quint16 id, size;
+ input >> id;
+ if (input.status() == QDataStream::ReadPastEnd)
+ return result;
+ input >> size;
+ if (input.status() == QDataStream::ReadPastEnd)
+ return result;
+ QByteArray data;
+ data.resize(size);
+ int read = input.readRawData(data.data(), data.size());
+ if (read < data.size())
+ return result;
+ result[id] << data;
+ }
+ return result;
+}
diff --git a/quazip/quazipfileinfo.h b/quazip/quazipfileinfo.h
--- a/quazip/quazipfileinfo.h
+++ b/quazip/quazipfileinfo.h
@@ -1,178 +1,226 @@
#ifndef QUA_ZIPFILEINFO_H
#define QUA_ZIPFILEINFO_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
-#include <QByteArray>
-#include <QDateTime>
-#include <QFile>
+#include <QtCore/QByteArray>
+#include <QtCore/QDateTime>
+#include <QtCore/QFile>
+#include <QtCore/QHash>
#include "quazip_global.h"
+/// The typedef to store extra field parse results
+typedef QHash<quint16, QList<QByteArray> > QuaExtraFieldHash;
+
/// Information about a file inside archive.
/**
* \deprecated Use QuaZipFileInfo64 instead. Not only it supports large files,
* but also more convenience methods as well.
*
* Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to
* fill this structure. */
struct QUAZIP_EXPORT QuaZipFileInfo {
/// File name.
QString name;
/// Version created by.
quint16 versionCreated;
/// Version needed to extract.
quint16 versionNeeded;
/// General purpose flags.
quint16 flags;
/// Compression method.
quint16 method;
/// Last modification date and time.
QDateTime dateTime;
/// CRC.
quint32 crc;
/// Compressed file size.
quint32 compressedSize;
/// Uncompressed file size.
quint32 uncompressedSize;
/// Disk number start.
quint16 diskNumberStart;
/// Internal file attributes.
quint16 internalAttr;
/// External file attributes.
quint32 externalAttr;
/// Comment.
QString comment;
/// Extra field.
QByteArray extra;
/// Get the file permissions.
/**
Returns the high 16 bits of external attributes converted to
QFile::Permissions.
*/
QFile::Permissions getPermissions() const;
};
/// Information about a file inside archive (with zip64 support).
/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to
* fill this structure. */
struct QUAZIP_EXPORT QuaZipFileInfo64 {
/// File name.
QString name;
/// Version created by.
quint16 versionCreated;
/// Version needed to extract.
quint16 versionNeeded;
/// General purpose flags.
quint16 flags;
/// Compression method.
quint16 method;
/// Last modification date and time.
/**
* This is the time stored in the standard ZIP header. This format only allows
* to store time with 2-second precision, so the seconds will always be even
* and the milliseconds will always be zero. If you need more precise
* date and time, you can try to call the getNTFSmTime() function or
* its siblings, provided that the archive itself contains these NTFS times.
*/
QDateTime dateTime;
/// CRC.
quint32 crc;
/// Compressed file size.
quint64 compressedSize;
/// Uncompressed file size.
quint64 uncompressedSize;
/// Disk number start.
quint16 diskNumberStart;
/// Internal file attributes.
quint16 internalAttr;
/// External file attributes.
quint32 externalAttr;
/// Comment.
QString comment;
/// Extra field.
QByteArray extra;
/// Get the file permissions.
/**
Returns the high 16 bits of external attributes converted to
QFile::Permissions.
*/
QFile::Permissions getPermissions() const;
/// Converts to QuaZipFileInfo
/**
If any of the fields are greater than 0xFFFFFFFFu, they are set to
0xFFFFFFFFu exactly, not just truncated. This function should be mainly used
for compatibility with the old code expecting QuaZipFileInfo, in the cases
when it's impossible or otherwise unadvisable (due to ABI compatibility
reasons, for example) to modify that old code to use QuaZipFileInfo64.
\return \c true if all fields converted correctly, \c false if an overflow
occured.
*/
bool toQuaZipFileInfo(QuaZipFileInfo &info) const;
/// Returns the NTFS modification time
/**
* The getNTFS*Time() functions only work if there is an NTFS extra field
* present. Otherwise, they all return invalid null timestamps.
* @param fineTicks If not NULL, the fractional part of milliseconds returned
* there, measured in 100-nanosecond ticks. Will be set to
* zero if there is no NTFS extra field.
* @sa dateTime
* @sa getNTFSaTime()
* @sa getNTFScTime()
* @return The NTFS modification time, UTC
*/
QDateTime getNTFSmTime(int *fineTicks = NULL) const;
/// Returns the NTFS access time
/**
* The getNTFS*Time() functions only work if there is an NTFS extra field
* present. Otherwise, they all return invalid null timestamps.
* @param fineTicks If not NULL, the fractional part of milliseconds returned
* there, measured in 100-nanosecond ticks. Will be set to
* zero if there is no NTFS extra field.
* @sa dateTime
* @sa getNTFSmTime()
* @sa getNTFScTime()
* @return The NTFS access time, UTC
*/
QDateTime getNTFSaTime(int *fineTicks = NULL) const;
/// Returns the NTFS creation time
/**
* The getNTFS*Time() functions only work if there is an NTFS extra field
* present. Otherwise, they all return invalid null timestamps.
* @param fineTicks If not NULL, the fractional part of milliseconds returned
* there, measured in 100-nanosecond ticks. Will be set to
* zero if there is no NTFS extra field.
* @sa dateTime
* @sa getNTFSmTime()
* @sa getNTFSaTime()
* @return The NTFS creation time, UTC
*/
QDateTime getNTFScTime(int *fineTicks = NULL) const;
+ /// Returns the extended modification timestamp
+ /**
+ * The getExt*Time() functions only work if there is an extended timestamp
+ * extra field (ID 0x5455) present. Otherwise, they all return invalid null
+ * timestamps.
+ *
+ * QuaZipFileInfo64 only contains the modification time because it's extracted
+ * from @ref extra, which contains the global extra field, and access and
+ * creation time are in the local header which can be accessed through
+ * @ref QuaZipFile.
+ *
+ * @sa dateTime
+ * @sa QuaZipFile::getExtModTime()
+ * @sa QuaZipFile::getExtAcTime()
+ * @sa QuaZipFile::getExtCrTime()
+ * @return The extended modification time, UTC
+ */
+ QDateTime getExtModTime() const;
/// Checks whether the file is encrypted.
bool isEncrypted() const {return (flags & 1) != 0;}
+ /// Parses extra field
+ /**
+ * The returned hash table contains a list of data blocks for every header ID
+ * in the provided extra field. The number of data blocks in a hash table value
+ * equals to the number of occurrences of the appropriate header id. In most cases,
+ * a block with a specific header ID only occurs once, and therefore the returned
+ * hash table will contain a list consisting of a single element for that header ID.
+ *
+ * @param extraField extra field to parse
+ * @return header id to list of data block hash
+ */
+ static QuaExtraFieldHash parseExtraField(const QByteArray &extraField);
+ /// Extracts extended time from the extra field
+ /**
+ * Utility function used by various getExt*Time() functions, but can be used directly
+ * if the extra field is obtained elsewhere (from a third party library, for example).
+ *
+ * @param extra the extra field for a file
+ * @param flag 1 - modification time, 2 - access time, 4 - creation time
+ * @return the extracted time or null QDateTime if not present
+ * @sa getExtModTime()
+ * @sa QuaZipFile::getExtModTime()
+ * @sa QuaZipFile::getExtAcTime()
+ * @sa QuaZipFile::getExtCrTime()
+ */
+ static QDateTime getExtTime(const QByteArray &extra, int flag);
};
#endif
diff --git a/quazip/quazipnewinfo.cpp b/quazip/quazipnewinfo.cpp
--- a/quazip/quazipnewinfo.cpp
+++ b/quazip/quazipnewinfo.cpp
@@ -1,286 +1,290 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
-#include <QFileInfo>
+#include <QtCore/QFileInfo>
#include "quazipnewinfo.h"
#include <string.h>
static void QuaZipNewInfo_setPermissions(QuaZipNewInfo *info,
QFile::Permissions perm, bool isDir, bool isSymLink = false)
{
quint32 uPerm = isDir ? 0040000 : 0100000;
if ( isSymLink ) {
#ifdef Q_OS_WIN
uPerm = 0200000;
#else
uPerm = 0120000;
#endif
}
if ((perm & QFile::ReadOwner) != 0)
uPerm |= 0400;
if ((perm & QFile::WriteOwner) != 0)
uPerm |= 0200;
if ((perm & QFile::ExeOwner) != 0)
uPerm |= 0100;
if ((perm & QFile::ReadGroup) != 0)
uPerm |= 0040;
if ((perm & QFile::WriteGroup) != 0)
uPerm |= 0020;
if ((perm & QFile::ExeGroup) != 0)
uPerm |= 0010;
if ((perm & QFile::ReadOther) != 0)
uPerm |= 0004;
if ((perm & QFile::WriteOther) != 0)
uPerm |= 0002;
if ((perm & QFile::ExeOther) != 0)
uPerm |= 0001;
info->externalAttr = (info->externalAttr & ~0xFFFF0000u) | (uPerm << 16);
}
template<typename FileInfo>
void QuaZipNewInfo_init(QuaZipNewInfo &self, const FileInfo &existing)
{
self.name = existing.name;
self.dateTime = existing.dateTime;
self.internalAttr = existing.internalAttr;
self.externalAttr = existing.externalAttr;
self.comment = existing.comment;
self.extraLocal = existing.extra;
self.extraGlobal = existing.extra;
self.uncompressedSize = existing.uncompressedSize;
}
QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo &existing)
{
QuaZipNewInfo_init(*this, existing);
}
QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo64 &existing)
{
QuaZipNewInfo_init(*this, existing);
}
QuaZipNewInfo::QuaZipNewInfo(const QString& name):
name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0),
uncompressedSize(0)
{
}
QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file):
name(name), internalAttr(0), externalAttr(0), uncompressedSize(0)
{
QFileInfo info(file);
QDateTime lm = info.lastModified();
if (!info.exists()) {
dateTime = QDateTime::currentDateTime();
} else {
dateTime = lm;
QuaZipNewInfo_setPermissions(this, info.permissions(), info.isDir(), info.isSymLink());
}
}
void QuaZipNewInfo::setFileDateTime(const QString& file)
{
QFileInfo info(file);
QDateTime lm = info.lastModified();
if (info.exists())
dateTime = lm;
}
void QuaZipNewInfo::setFilePermissions(const QString &file)
{
QFileInfo info = QFileInfo(file);
QFile::Permissions perm = info.permissions();
QuaZipNewInfo_setPermissions(this, perm, info.isDir(), info.isSymLink());
}
void QuaZipNewInfo::setPermissions(QFile::Permissions permissions)
{
- QuaZipNewInfo_setPermissions(this, permissions, name.endsWith('/'));
+ QuaZipNewInfo_setPermissions(this, permissions, name.endsWith(QLatin1String("/")));
}
void QuaZipNewInfo::setFileNTFSTimes(const QString &fileName)
{
QFileInfo fi(fileName);
if (!fi.exists()) {
qWarning("QuaZipNewInfo::setFileNTFSTimes(): '%s' doesn't exist",
fileName.toUtf8().constData());
return;
}
setFileNTFSmTime(fi.lastModified());
setFileNTFSaTime(fi.lastRead());
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
+ setFileNTFScTime(fi.birthTime());
+#else
setFileNTFScTime(fi.created());
+#endif
}
static void setNTFSTime(QByteArray &extra, const QDateTime &time, int position,
int fineTicks) {
int ntfsPos = -1, timesPos = -1;
unsigned ntfsLength = 0, ntfsTimesLength = 0;
for (int i = 0; i <= extra.size() - 4; ) {
unsigned type = static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i)))
| (static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i + 1))) << 8);
i += 2;
unsigned length = static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i)))
| (static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i + 1))) << 8);
i += 2;
if (type == QUAZIP_EXTRA_NTFS_MAGIC) {
ntfsPos = i - 4; // the beginning of the NTFS record
ntfsLength = length;
if (length <= 4) {
break; // no times in the NTFS record
}
i += 4; // reserved
while (i <= extra.size() - 4) {
unsigned tag = static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i)))
| (static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i + 1)))
<< 8);
i += 2;
unsigned tagsize = static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i)))
| (static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i + 1)))
<< 8);
i += 2;
if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC) {
timesPos = i - 4; // the beginning of the NTFS times tag
ntfsTimesLength = tagsize;
break;
} else {
i += tagsize;
}
}
break; // I ain't going to search for yet another NTFS record!
} else {
i += length;
}
}
if (ntfsPos == -1) {
// No NTFS record, need to create one.
ntfsPos = extra.size();
ntfsLength = 32;
extra.resize(extra.size() + 4 + ntfsLength);
// the NTFS record header
extra[ntfsPos] = static_cast<char>(QUAZIP_EXTRA_NTFS_MAGIC);
extra[ntfsPos + 1] = static_cast<char>(QUAZIP_EXTRA_NTFS_MAGIC >> 8);
extra[ntfsPos + 2] = 32; // the 2-byte size in LittleEndian
extra[ntfsPos + 3] = 0;
// zero the record
memset(extra.data() + ntfsPos + 4, 0, 32);
timesPos = ntfsPos + 8;
// now set the tag data
extra[timesPos] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC);
extra[timesPos + 1] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC
>> 8);
// the size:
extra[timesPos + 2] = 24;
extra[timesPos + 3] = 0;
ntfsTimesLength = 24;
}
if (timesPos == -1) {
// No time tag in the NTFS record, need to add one.
timesPos = ntfsPos + 4 + ntfsLength;
extra.resize(extra.size() + 28);
// Now we need to move the rest of the field
// (possibly zero bytes, but memmove() is OK with that).
// 0 ......... ntfsPos .. ntfsPos + 4 ... timesPos
// <some data> <header> <NTFS record> <need-to-move data> <end>
memmove(extra.data() + timesPos + 28, extra.data() + timesPos,
extra.size() - 28 - timesPos);
ntfsLength += 28;
// now set the tag data
extra[timesPos] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC);
extra[timesPos + 1] = static_cast<char>(QUAZIP_EXTRA_NTFS_TIME_MAGIC
>> 8);
// the size:
extra[timesPos + 2] = 24;
extra[timesPos + 3] = 0;
// zero the record
memset(extra.data() + timesPos + 4, 0, 24);
ntfsTimesLength = 24;
}
if (ntfsTimesLength < 24) {
// Broken times field. OK, this is really unlikely, but just in case...
size_t timesEnd = timesPos + 4 + ntfsTimesLength;
extra.resize(extra.size() + (24 - ntfsTimesLength));
// Move it!
// 0 ......... timesPos .... timesPos + 4 .. timesEnd
// <some data> <time header> <broken times> <need-to-move data> <end>
memmove(extra.data() + timesEnd + (24 - ntfsTimesLength),
extra.data() + timesEnd,
extra.size() - (24 - ntfsTimesLength) - timesEnd);
// Now we have to increase the NTFS record and time tag lengths.
ntfsLength += (24 - ntfsTimesLength);
ntfsTimesLength = 24;
extra[ntfsPos + 2] = static_cast<char>(ntfsLength);
extra[ntfsPos + 3] = static_cast<char>(ntfsLength >> 8);
extra[timesPos + 2] = static_cast<char>(ntfsTimesLength);
extra[timesPos + 3] = static_cast<char>(ntfsTimesLength >> 8);
}
QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
#if (QT_VERSION >= 0x040700)
quint64 ticks = base.msecsTo(time) * 10000 + fineTicks;
#else
QDateTime utc = time.toUTC();
quint64 ticks = (static_cast<qint64>(base.date().daysTo(utc.date()))
* Q_INT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(utc.time())))
* Q_INT64_C(10000) + fineTicks;
#endif
extra[timesPos + 4 + position] = static_cast<char>(ticks);
extra[timesPos + 5 + position] = static_cast<char>(ticks >> 8);
extra[timesPos + 6 + position] = static_cast<char>(ticks >> 16);
extra[timesPos + 7 + position] = static_cast<char>(ticks >> 24);
extra[timesPos + 8 + position] = static_cast<char>(ticks >> 32);
extra[timesPos + 9 + position] = static_cast<char>(ticks >> 40);
extra[timesPos + 10 + position] = static_cast<char>(ticks >> 48);
extra[timesPos + 11 + position] = static_cast<char>(ticks >> 56);
}
void QuaZipNewInfo::setFileNTFSmTime(const QDateTime &mTime, int fineTicks)
{
setNTFSTime(extraLocal, mTime, 0, fineTicks);
setNTFSTime(extraGlobal, mTime, 0, fineTicks);
}
void QuaZipNewInfo::setFileNTFSaTime(const QDateTime &aTime, int fineTicks)
{
setNTFSTime(extraLocal, aTime, 8, fineTicks);
setNTFSTime(extraGlobal, aTime, 8, fineTicks);
}
void QuaZipNewInfo::setFileNTFScTime(const QDateTime &cTime, int fineTicks)
{
setNTFSTime(extraLocal, cTime, 16, fineTicks);
setNTFSTime(extraGlobal, cTime, 16, fineTicks);
}
diff --git a/quazip/quazipnewinfo.h b/quazip/quazipnewinfo.h
--- a/quazip/quazipnewinfo.h
+++ b/quazip/quazipnewinfo.h
@@ -1,207 +1,208 @@
#ifndef QUA_ZIPNEWINFO_H
#define QUA_ZIPNEWINFO_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant, see
quazip/(un)zip.h files for details, basically it's zlib license.
**/
-#include <QDateTime>
-#include <QFile>
-#include <QString>
+#include <QtCore/QDateTime>
+#include <QtCore/QFile>
+#include <QtCore/QString>
#include "quazip_global.h"
#include "quazipfileinfo.h"
/// Information about a file to be created.
/** This structure holds information about a file to be created inside
* ZIP archive. At least name should be set to something correct before
* passing this structure to
* QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool).
*
* Zip64 support of this structure is slightly limited: in the raw mode (when
* a pre-compressed file is written into a ZIP file as-is), it is necessary
* to specify the uncompressed file size and the appropriate field is 32 bit.
* Since the raw mode is used extremely rare, there is no real need to have
* a separate QuaZipNewInfo64 structure like QuaZipFileInfo64. It may be added
* in the future though, if there is a demand for the raw mode with zip64
* archives.
**/
struct QUAZIP_EXPORT QuaZipNewInfo {
/// File name.
/** This field holds file name inside archive, including path relative
* to archive root.
**/
QString name;
/// File timestamp.
/** This is the last file modification date and time. Will be stored
* in the archive central directory. It is a good practice to set it
* to the source file timestamp instead of archive creating time. Use
* setFileDateTime() or QuaZipNewInfo(const QString&, const QString&).
**/
QDateTime dateTime;
/// File internal attributes.
quint16 internalAttr;
/// File external attributes.
/**
The highest 16 bits contain Unix file permissions and type (dir or
file). The constructor QuaZipNewInfo(const QString&, const QString&)
takes permissions from the provided file.
*/
quint32 externalAttr;
/// File comment.
- /** Will be encoded using QuaZip::getCommentCodec().
+ /** Will be encoded in UTF-8 encoding.
**/
QString comment;
/// File local extra field.
QByteArray extraLocal;
/// File global extra field.
QByteArray extraGlobal;
/// Uncompressed file size.
/** This is only needed if you are using raw file zipping mode, i. e.
* adding precompressed file in the zip archive.
**/
ulong uncompressedSize;
/// Constructs QuaZipNewInfo instance.
/** Initializes name with \a name, dateTime with current date and
* time. Attributes are initialized with zeros, comment and extra
* field with null values.
**/
QuaZipNewInfo(const QString& name);
/// Constructs QuaZipNewInfo instance.
/** Initializes name with \a name. Timestamp and permissions are taken
* from the specified file. If the \a file does not exists or its timestamp
* is inaccessible (e. g. you do not have read permission for the
* directory file in), uses current time and zero permissions. Other attributes are
* initialized with zeros, comment and extra field with null values.
*
* \sa setFileDateTime()
**/
QuaZipNewInfo(const QString& name, const QString& file);
/// Initializes the new instance from existing file info.
/** Mainly used when copying files between archives.
*
* Both extra fields are initialized to existing.extra.
* @brief QuaZipNewInfo
* @param existing
*/
QuaZipNewInfo(const QuaZipFileInfo &existing);
/// Initializes the new instance from existing file info.
/** Mainly used when copying files between archives.
*
* Both extra fields are initialized to existing.extra.
* @brief QuaZipNewInfo
* @param existing
*/
QuaZipNewInfo(const QuaZipFileInfo64 &existing);
/// Sets the file timestamp from the existing file.
/** Use this function to set the file timestamp from the existing
* file. Use it like this:
* \code
* QuaZipFile zipFile(&zip);
* QFile file("file-to-add");
* file.open(QIODevice::ReadOnly);
* QuaZipNewInfo info("file-name-in-archive");
* info.setFileDateTime("file-to-add"); // take the timestamp from file
* zipFile.open(QIODevice::WriteOnly, info);
* \endcode
*
* This function does not change dateTime if some error occured (e. g.
* file is inaccessible).
**/
void setFileDateTime(const QString& file);
/// Sets the file permissions from the existing file.
/**
Takes permissions from the file and sets the high 16 bits of
external attributes. Uses QFileInfo to get permissions on all
platforms.
*/
void setFilePermissions(const QString &file);
/// Sets the file permissions.
/**
Modifies the highest 16 bits of external attributes. The type part
is set to dir if the name ends with a slash, and to regular file
otherwise.
*/
void setPermissions(QFile::Permissions permissions);
/// Sets the NTFS times from an existing file.
/**
* If the file doesn't exist, a warning is printed to the stderr and nothing
* is done. Otherwise, all three times, as reported by
- * QFileInfo::lastModified(), QFileInfo::lastRead() and QFileInfo::created(),
- * are written to the NTFS extra field record.
+ * QFileInfo::lastModified(), QFileInfo::lastRead() and
+ * QFileInfo::birthTime() (>=Qt5.10) or QFileInfo::created(), are written to
+ * the NTFS extra field record.
*
* The NTFS record is written to
* both the local and the global extra fields, updating the existing record
* if there is one, or creating a new one and appending it to the end
* of each extra field.
*
* The microseconds will be zero, as they aren't reported by QFileInfo.
* @param fileName
*/
void setFileNTFSTimes(const QString &fileName);
/// Sets the NTFS modification time.
/**
* The time is written into the NTFS record in
* both the local and the global extra fields, updating the existing record
* if there is one, or creating a new one and appending it to the end
* of each extra field. When updating an existing record, all other fields
* are left intact.
* @param mTime The new modification time.
* @param fineTicks The fractional part of milliseconds, in 100-nanosecond
* ticks (i. e. 9999 ticks = 999.9 microsecond). Values greater than
* 9999 will add milliseconds or even seconds, but this can be
* confusing and therefore is discouraged.
*/
void setFileNTFSmTime(const QDateTime &mTime, int fineTicks = 0);
/// Sets the NTFS access time.
/**
* The time is written into the NTFS record in
* both the local and the global extra fields, updating the existing record
* if there is one, or creating a new one and appending it to the end
* of each extra field. When updating an existing record, all other fields
* are left intact.
* @param aTime The new access time.
* @param fineTicks The fractional part of milliseconds, in 100-nanosecond
* ticks (i. e. 9999 ticks = 999.9 microsecond). Values greater than
* 9999 will add milliseconds or even seconds, but this can be
* confusing and therefore is discouraged.
*/
void setFileNTFSaTime(const QDateTime &aTime, int fineTicks = 0);
/// Sets the NTFS creation time.
/**
* The time is written into the NTFS record in
* both the local and the global extra fields, updating the existing record
* if there is one, or creating a new one and appending it to the end
* of each extra field. When updating an existing record, all other fields
* are left intact.
* @param cTime The new creation time.
* @param fineTicks The fractional part of milliseconds, in 100-nanosecond
* ticks (i. e. 9999 ticks = 999.9 microsecond). Values greater than
* 9999 will add milliseconds or even seconds, but this can be
* confusing and therefore is discouraged.
*/
void setFileNTFScTime(const QDateTime &cTime, int fineTicks = 0);
};
#endif
diff --git a/quazip/unzip.c b/quazip/unzip.c
--- a/quazip/unzip.c
+++ b/quazip/unzip.c
@@ -1,2067 +1,2080 @@
/* unzip.c -- IO for uncompress .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications of Unzip for Zip64
Copyright (C) 2007-2008 Even Rouault
Modifications for Zip64 support on both zip and unzip
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
Modifications for QIODevice support and other QuaZIP fixes
Copyright (C) 2005-2014 Sergey A. Tachenov
For more info read MiniZip_info.txt
Modifications for static code analysis report
Copyright (C) 2016 Intel Deutschland GmbH
------------------------------------------------------------------------------------
Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
compatibility with older software. The following is from the original crypt.c.
Code woven in by Terry Thorsen 1/2003.
Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
See the accompanying file LICENSE, version 2000-Apr-09 or later
(the contents of which are also included in zip.h) for terms of use.
If, for some reason, all these files are missing, the Info-ZIP license
also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
crypt.c (full version) by Info-ZIP. Last revised: [see minizip_crypt.h]
The encryption/decryption parts of this source code (as opposed to the
non-echoing password parts) were originally written in Europe. The
whole source package can be freely distributed, including from the USA.
(Prior to January 2000, re-export from the US was a violation of US law.)
This encryption code is a direct transcription of the algorithm from
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
file (appnote.txt) is distributed with the PKZIP program (even in the
version without encryption capabilities).
------------------------------------------------------------------------------------
Changes in unzip.c
2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos
2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
2007-2008 - Even Rouault - Remove old C style function prototypes
2007-2008 - Even Rouault - Add unzip support for ZIP64
Copyright (C) 2007-2008 Even Rouault
Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
should only read the compressed/uncompressed size from the Zip64 format if
the size from normal header was 0xFFFFFFFF
Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant
Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required)
Patch created by Daniel Borca
Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "zlib.h"
+#include <zlib.h>
#if (ZLIB_VERNUM < 0x1270)
typedef uLongf z_crc_t;
#endif
#include "unzip.h"
#ifdef STDC
# include <stddef.h>
# include <string.h>
# include <stdlib.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
#ifndef CASESENSITIVITYDEFAULT_NO
# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
# define CASESENSITIVITYDEFAULT_NO
# endif
#endif
#ifndef UNZ_BUFSIZE
#define UNZ_BUFSIZE (16384)
#endif
#ifndef UNZ_MAXFILENAMEINZIP
#define UNZ_MAXFILENAMEINZIP (256)
#endif
#ifndef ALLOC
# define ALLOC(size) (malloc(size))
#endif
#ifndef TRYFREE
# define TRYFREE(p) {if (p) free(p);}
#endif
#define SIZECENTRALDIRITEM (0x2e)
#define SIZEZIPLOCALHEADER (0x1e)
const char unz_copyright[] =
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
/* unz_file_info_interntal contain internal info about a file in zipfile*/
typedef struct unz_file_info64_internal_s
{
ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
} unz_file_info64_internal;
/* file_in_zip_read_info_s contain internal information about a file in zipfile,
when reading and decompress it */
typedef struct
{
char *read_buffer; /* internal buffer for compressed data */
z_stream stream; /* zLib stream structure for inflate */
ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
uLong stream_initialised; /* flag set if stream structure is initialised*/
ZPOS64_T offset_local_extrafield;/* offset of the local extra field */
uInt size_local_extrafield;/* size of the local extra field */
ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/
ZPOS64_T total_out_64;
uLong crc32; /* crc32 of all data uncompressed */
uLong crc32_wait; /* crc32 we must obtain after decompress all */
ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
zlib_filefunc64_32_def z_filefunc;
voidpf filestream; /* io structore of the zipfile */
uLong compression_method; /* compression method (0==store) */
ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
int raw;
} file_in_zip64_read_info_s;
/* unz64_s contain internal information about the zipfile
*/
typedef struct
{
zlib_filefunc64_32_def z_filefunc;
int is64bitOpenFunction;
voidpf filestream; /* io structore of the zipfile */
unz_global_info64 gi; /* public global information */
ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
ZPOS64_T num_file; /* number of the current file in the zipfile*/
ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/
ZPOS64_T current_file_ok; /* flag about the usability of the current file*/
ZPOS64_T central_pos; /* position of the beginning of the central dir*/
ZPOS64_T size_central_dir; /* size of the central directory */
ZPOS64_T offset_central_dir; /* offset of start of central directory with
respect to the starting disk number */
unz_file_info64 cur_file_info; /* public info about the current file in zip*/
unz_file_info64_internal cur_file_info_internal; /* private info about it*/
file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current
file if we are decompressing it */
int encrypted;
int isZip64;
unsigned flags;
# ifndef NOUNCRYPT
unsigned long keys[3]; /* keys defining the pseudo-random sequence */
const z_crc_t FAR * pcrc_32_tab;
# endif
} unz64_s;
#ifndef NOUNCRYPT
#include "minizip_crypt.h"
#endif
/* ===========================================================================
Read a byte from a gz_stream; update next_in and avail_in. Return EOF
for end of file.
IN assertion: the stream s has been sucessfully opened for reading.
*/
local int unz64local_getByte OF((
const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
int *pi));
local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)
{
unsigned char c;
int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
if (err==1)
{
*pi = (int)c;
return UNZ_OK;
}
else
{
if (ZERROR64(*pzlib_filefunc_def,filestream))
return UNZ_ERRNO;
else
return UNZ_EOF;
}
}
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
local int unz64local_getShort OF((
const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX));
local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX)
{
uLong x ;
int i = 0;
int err;
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (uLong)i;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((uLong)i)<<8;
if (err==UNZ_OK)
*pX = x;
else
*pX = 0;
return err;
}
local int unz64local_getLong OF((
const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX));
local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
uLong *pX)
{
uLong x ;
int i = 0;
int err;
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (uLong)i;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((uLong)i)<<8;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((uLong)i)<<16;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((uLong)i)<<24;
if (err==UNZ_OK)
*pX = x;
else
*pX = 0;
return err;
}
local int unz64local_getLong64 OF((
const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
ZPOS64_T *pX));
local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream,
ZPOS64_T *pX)
{
ZPOS64_T x ;
int i = 0;
int err;
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (ZPOS64_T)i;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<8;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<16;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<24;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<32;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<40;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<48;
if (err==UNZ_OK)
err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
x |= ((ZPOS64_T)i)<<56;
if (err==UNZ_OK)
*pX = x;
else
*pX = 0;
return err;
}
/* My own strcmpi / strcasecmp */
local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2)
{
for (;;)
{
char c1=*(fileName1++);
char c2=*(fileName2++);
if ((c1>='a') && (c1<='z'))
c1 -= 0x20;
if ((c2>='a') && (c2<='z'))
c2 -= 0x20;
if (c1=='\0')
return ((c2=='\0') ? 0 : -1);
if (c2=='\0')
return 1;
if (c1<c2)
return -1;
if (c1>c2)
return 1;
}
}
#ifdef CASESENSITIVITYDEFAULT_NO
#define CASESENSITIVITYDEFAULTVALUE 2
#else
#define CASESENSITIVITYDEFAULTVALUE 1
#endif
#ifndef STRCMPCASENOSENTIVEFUNCTION
#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
#endif
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
const char* fileName2,
int iCaseSensitivity)
{
if (iCaseSensitivity==0)
iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
if (iCaseSensitivity==1)
return strcmp(fileName1,fileName2);
return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
}
#ifndef BUFREADCOMMENT
#define BUFREADCOMMENT (0x400)
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
{
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=0;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
return 0;
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
return 0;
uBackRead = 4;
while (uBackRead<uMaxBack)
{
uLong uReadSize;
ZPOS64_T uReadPos ;
int i;
if (uBackRead+BUFREADCOMMENT>uMaxBack)
uBackRead = uMaxBack;
else
uBackRead+=BUFREADCOMMENT;
uReadPos = uSizeFile-uBackRead ;
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
(BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
break;
if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
break;
for (i=(int)uReadSize-3; (i--)>0;)
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
{
uPosFound = uReadPos+i;
break;
}
if (uPosFound!=0)
break;
}
TRYFREE(buf);
return uPosFound;
}
/*
Locate the Central directory 64 of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T unz64local_SearchCentralDir64 OF((
const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream));
local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
voidpf filestream)
{
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=0;
uLong uL;
ZPOS64_T relativeOffset;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
return 0;
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
return 0;
uBackRead = 4;
while (uBackRead<uMaxBack)
{
uLong uReadSize;
ZPOS64_T uReadPos;
int i;
if (uBackRead+BUFREADCOMMENT>uMaxBack)
uBackRead = uMaxBack;
else
uBackRead+=BUFREADCOMMENT;
uReadPos = uSizeFile-uBackRead ;
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
(BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
break;
if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
break;
for (i=(int)uReadSize-3; (i--)>0;)
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
{
uPosFound = uReadPos+i;
break;
}
if (uPosFound!=0)
break;
}
TRYFREE(buf);
if (uPosFound == 0)
return 0;
/* Zip64 end of central directory locator */
if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
return 0;
/* the signature, already checked */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return 0;
/* number of the disk with the start of the zip64 end of central directory */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return 0;
if (uL != 0)
return 0;
/* relative offset of the zip64 end of central directory record */
if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
return 0;
/* total number of disks */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return 0;
if (uL != 1)
return 0;
/* Goto end of central directory record */
if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
return 0;
/* the signature */
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
return 0;
if (uL != 0x06064b50)
return 0;
return relativeOffset;
}
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
"zlib/zlib114.zip".
If the zipfile cannot be opened (file doesn't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
extern unzFile unzOpenInternal (voidpf file,
zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
int is64bitOpenFunction, unsigned flags)
{
unz64_s us;
unz64_s *s;
ZPOS64_T central_pos;
uLong uL;
uLong number_disk; /* number of the current dist, used for
spaning ZIP, unsupported, always 0*/
uLong number_disk_with_CD; /* number the the disk with central dir, used
for spaning ZIP, unsupported, always 0*/
ZPOS64_T number_entry_CD; /* total number of entries in
the central dir
(same than number_entry on nospan) */
int err=UNZ_OK;
if (unz_copyright[0]!=' ')
return NULL;
us.flags = flags;
us.z_filefunc.zseek32_file = NULL;
us.z_filefunc.ztell32_file = NULL;
if (pzlib_filefunc64_32_def==NULL)
fill_qiodevice64_filefunc(&us.z_filefunc.zfile_func64);
else
us.z_filefunc = *pzlib_filefunc64_32_def;
us.is64bitOpenFunction = is64bitOpenFunction;
us.filestream = ZOPEN64(us.z_filefunc,
file,
ZLIB_FILEFUNC_MODE_READ |
ZLIB_FILEFUNC_MODE_EXISTING);
if (us.filestream==NULL)
return NULL;
central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
if (central_pos)
{
uLong uS;
ZPOS64_T uL64;
us.isZip64 = 1;
if (ZSEEK64(us.z_filefunc, us.filestream,
central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
err=UNZ_ERRNO;
/* the signature, already checked */
if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
err=UNZ_ERRNO;
/* size of zip64 end of central directory record */
if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
err=UNZ_ERRNO;
/* version made by */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
err=UNZ_ERRNO;
/* version needed to extract */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
err=UNZ_ERRNO;
/* number of this disk */
if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
err=UNZ_ERRNO;
/* number of the disk with the start of the central directory */
if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
err=UNZ_ERRNO;
/* total number of entries in the central directory on this disk */
if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
err=UNZ_ERRNO;
/* total number of entries in the central directory */
if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
err=UNZ_ERRNO;
if ((number_entry_CD!=us.gi.number_entry) ||
(number_disk_with_CD!=0) ||
(number_disk!=0))
err=UNZ_BADZIPFILE;
/* size of the central directory */
if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
err=UNZ_ERRNO;
/* offset of start of central directory with respect to the
starting disk number */
if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
err=UNZ_ERRNO;
us.gi.size_comment = 0;
}
else
{
central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
if (central_pos==0)
err=UNZ_ERRNO;
us.isZip64 = 0;
if (ZSEEK64(us.z_filefunc, us.filestream,
central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
err=UNZ_ERRNO;
/* the signature, already checked */
if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
err=UNZ_ERRNO;
/* number of this disk */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
err=UNZ_ERRNO;
/* number of the disk with the start of the central directory */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
err=UNZ_ERRNO;
/* total number of entries in the central dir on this disk */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
err=UNZ_ERRNO;
us.gi.number_entry = uL;
/* total number of entries in the central dir */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
err=UNZ_ERRNO;
number_entry_CD = uL;
if ((number_entry_CD!=us.gi.number_entry) ||
(number_disk_with_CD!=0) ||
(number_disk!=0))
err=UNZ_BADZIPFILE;
/* size of the central directory */
if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
err=UNZ_ERRNO;
us.size_central_dir = uL;
/* offset of start of central directory with respect to the
starting disk number */
if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
err=UNZ_ERRNO;
us.offset_central_dir = uL;
/* zipfile comment length */
if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
err=UNZ_ERRNO;
}
if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
(err==UNZ_OK))
err=UNZ_BADZIPFILE;
if (err!=UNZ_OK)
{
if ((us.flags & UNZ_AUTO_CLOSE) != 0)
ZCLOSE64(us.z_filefunc, us.filestream);
else
ZFAKECLOSE64(us.z_filefunc, us.filestream);
return NULL;
}
us.byte_before_the_zipfile = central_pos -
(us.offset_central_dir+us.size_central_dir);
us.central_pos = central_pos;
us.pfile_in_zip_read = NULL;
us.encrypted = 0;
s=(unz64_s*)ALLOC(sizeof(unz64_s));
if( s != NULL)
{
*s=us;
unzGoToFirstFile((unzFile)s);
}
return (unzFile)s;
}
extern unzFile ZEXPORT unzOpen2 (voidpf file,
zlib_filefunc_def* pzlib_filefunc32_def)
{
if (pzlib_filefunc32_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
return unzOpenInternal(file, &zlib_filefunc64_32_def_fill, 0, UNZ_DEFAULT_FLAGS);
}
else
return unzOpenInternal(file, NULL, 0, UNZ_DEFAULT_FLAGS);
}
extern unzFile ZEXPORT unzOpen2_64 (voidpf file,
zlib_filefunc64_def* pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
zlib_filefunc64_32_def_fill.ztell32_file = NULL;
zlib_filefunc64_32_def_fill.zseek32_file = NULL;
return unzOpenInternal(file, &zlib_filefunc64_32_def_fill, 1, UNZ_DEFAULT_FLAGS);
}
else
return unzOpenInternal(file, NULL, 1, UNZ_DEFAULT_FLAGS);
}
extern unzFile ZEXPORT unzOpen (voidpf file)
{
return unzOpenInternal(file, NULL, 0, UNZ_DEFAULT_FLAGS);
}
extern unzFile ZEXPORT unzOpen64 (voidpf file)
{
return unzOpenInternal(file, NULL, 1, UNZ_DEFAULT_FLAGS);
}
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzClose (unzFile file)
{
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (s->pfile_in_zip_read!=NULL)
unzCloseCurrentFile(file);
if ((s->flags & UNZ_AUTO_CLOSE) != 0)
ZCLOSE64(s->z_filefunc, s->filestream);
else
ZFAKECLOSE64(s->z_filefunc, s->filestream);
TRYFREE(s);
return UNZ_OK;
}
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info)
{
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
*pglobal_info=s->gi;
return UNZ_OK;
}
extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32)
{
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
/* to do : check if number_entry is not truncated */
pglobal_info32->number_entry = (uLong)s->gi.number_entry;
pglobal_info32->size_comment = s->gi.size_comment;
return UNZ_OK;
}
+
+extern int ZEXPORT unzGetFileFlags (unzFile file, unsigned* pflags)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ *pflags = s->flags;
+ return UNZ_OK;
+}
+
/*
Translate date/time from Dos format to tm_unz (readable more easilty)
*/
local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm)
{
ZPOS64_T uDate;
uDate = (ZPOS64_T)(ulDosDate>>16);
ptm->tm_mday = (uInt)(uDate&0x1f) ;
ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
}
/*
Get Info about the current file in the zipfile, with internal only info
*/
local int unz64local_GetCurrentFileInfoInternal OF((unzFile file,
unz_file_info64 *pfile_info,
unz_file_info64_internal
*pfile_info_internal,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
local int unz64local_GetCurrentFileInfoInternal (unzFile file,
unz_file_info64 *pfile_info,
unz_file_info64_internal
*pfile_info_internal,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize)
{
unz64_s* s;
unz_file_info64 file_info;
unz_file_info64_internal file_info_internal;
int err=UNZ_OK;
uLong uMagic;
ZPOS64_T llSeek=0;
uLong uL;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (ZSEEK64(s->z_filefunc, s->filestream,
s->pos_in_central_dir+s->byte_before_the_zipfile,
ZLIB_FILEFUNC_SEEK_SET)!=0)
err=UNZ_ERRNO;
/* we check the magic */
if (err==UNZ_OK)
{
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
err=UNZ_ERRNO;
else if (uMagic!=0x02014b50)
err=UNZ_BADZIPFILE;
}
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
err=UNZ_ERRNO;
unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
err=UNZ_ERRNO;
file_info.compressed_size = uL;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
err=UNZ_ERRNO;
file_info.uncompressed_size = uL;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
err=UNZ_ERRNO;
/* relative offset of local header */
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
err=UNZ_ERRNO;
file_info_internal.offset_curfile = uL;
llSeek+=file_info.size_filename;
if ((err==UNZ_OK) && (szFileName!=NULL))
{
uLong uSizeRead ;
if (file_info.size_filename<fileNameBufferSize)
{
*(szFileName+file_info.size_filename)='\0';
uSizeRead = file_info.size_filename;
}
else
uSizeRead = fileNameBufferSize;
if ((file_info.size_filename>0) && (fileNameBufferSize>0))
if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
err=UNZ_ERRNO;
llSeek -= uSizeRead;
}
/* Read extrafield */
if ((err==UNZ_OK) && (extraField!=NULL))
{
ZPOS64_T uSizeRead ;
if (file_info.size_file_extra<extraFieldBufferSize)
uSizeRead = file_info.size_file_extra;
else
uSizeRead = extraFieldBufferSize;
if (llSeek!=0)
{
if (ZSEEK64(s->z_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
llSeek=0;
else
err=UNZ_ERRNO;
}
if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
err=UNZ_ERRNO;
llSeek += file_info.size_file_extra - (uLong)uSizeRead;
}
else
llSeek += file_info.size_file_extra;
if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
{
uLong acc = 0;
/* since lSeek now points to after the extra field we need to move back */
llSeek -= file_info.size_file_extra;
if (llSeek!=0)
{
if (ZSEEK64(s->z_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
llSeek=0;
else
err=UNZ_ERRNO;
}
while(acc < file_info.size_file_extra)
{
uLong headerId;
uLong dataSize;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
err=UNZ_ERRNO;
/* ZIP64 extra fields */
if (headerId == 0x0001)
{
uLong uL;
if(file_info.uncompressed_size == (ZPOS64_T)0xFFFFFFFFu)
{
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
err=UNZ_ERRNO;
}
if(file_info.compressed_size == (ZPOS64_T)0xFFFFFFFFu)
{
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
err=UNZ_ERRNO;
}
if(file_info_internal.offset_curfile == (ZPOS64_T)0xFFFFFFFFu)
{
/* Relative Header offset */
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
err=UNZ_ERRNO;
}
if(file_info.disk_num_start == 0xFFFFFFFFu)
{
/* Disk Start Number */
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
err=UNZ_ERRNO;
}
}
else
{
if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
err=UNZ_ERRNO;
}
acc += 2 + 2 + dataSize;
}
}
if ((err==UNZ_OK) && (szComment!=NULL))
{
uLong uSizeRead ;
if (file_info.size_file_comment<commentBufferSize)
{
*(szComment+file_info.size_file_comment)='\0';
uSizeRead = file_info.size_file_comment;
}
else
uSizeRead = commentBufferSize;
if (llSeek!=0)
{
if (ZSEEK64(s->z_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
llSeek=0;
else
err=UNZ_ERRNO;
}
if ((file_info.size_file_comment>0) && (commentBufferSize>0))
if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
err=UNZ_ERRNO;
llSeek+=file_info.size_file_comment - uSizeRead;
}
else
llSeek+=file_info.size_file_comment;
if ((err==UNZ_OK) && (pfile_info!=NULL))
*pfile_info=file_info;
if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
*pfile_info_internal=file_info_internal;
return err;
}
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem.
*/
extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file,
unz_file_info64 * pfile_info,
char * szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
char* szComment, uLong commentBufferSize)
{
return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,
szFileName,fileNameBufferSize,
extraField,extraFieldBufferSize,
szComment,commentBufferSize);
}
extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
unz_file_info * pfile_info,
char * szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
char* szComment, uLong commentBufferSize)
{
int err;
unz_file_info64 file_info64;
err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
szFileName,fileNameBufferSize,
extraField,extraFieldBufferSize,
szComment,commentBufferSize);
if (err==UNZ_OK && pfile_info != NULL)
{
pfile_info->version = file_info64.version;
pfile_info->version_needed = file_info64.version_needed;
pfile_info->flag = file_info64.flag;
pfile_info->compression_method = file_info64.compression_method;
pfile_info->dosDate = file_info64.dosDate;
pfile_info->crc = file_info64.crc;
pfile_info->size_filename = file_info64.size_filename;
pfile_info->size_file_extra = file_info64.size_file_extra;
pfile_info->size_file_comment = file_info64.size_file_comment;
pfile_info->disk_num_start = file_info64.disk_num_start;
pfile_info->internal_fa = file_info64.internal_fa;
pfile_info->external_fa = file_info64.external_fa;
pfile_info->tmu_date = file_info64.tmu_date,
pfile_info->compressed_size = (uLong)file_info64.compressed_size;
pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
}
return err;
}
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToFirstFile (unzFile file)
{
int err=UNZ_OK;
unz64_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
s->pos_in_central_dir=s->offset_central_dir;
s->num_file=0;
err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
s->current_file_ok = (err == UNZ_OK);
+ if (s->cur_file_info.flag & UNZ_ENCODING_UTF8)
+ unzSetFlags(file, UNZ_ENCODING_UTF8);
return err;
}
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzGoToNextFile (unzFile file)
{
unz64_s* s;
int err;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
return UNZ_END_OF_LIST_OF_FILE;
if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
if (s->num_file+1==s->gi.number_entry)
return UNZ_END_OF_LIST_OF_FILE;
s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
s->num_file++;
err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
s->current_file_ok = (err == UNZ_OK);
return err;
}
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzipStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)
{
unz64_s* s;
int err;
/* We remember the 'current' position in the file so that we can jump
* back there if we fail.
*/
unz_file_info64 cur_file_infoSaved;
unz_file_info64_internal cur_file_info_internalSaved;
ZPOS64_T num_fileSaved;
ZPOS64_T pos_in_central_dirSaved;
if (file==NULL)
return UNZ_PARAMERROR;
if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
return UNZ_END_OF_LIST_OF_FILE;
/* Save the current state */
num_fileSaved = s->num_file;
pos_in_central_dirSaved = s->pos_in_central_dir;
cur_file_infoSaved = s->cur_file_info;
cur_file_info_internalSaved = s->cur_file_info_internal;
err = unzGoToFirstFile(file);
while (err == UNZ_OK)
{
char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
err = unzGetCurrentFileInfo64(file,NULL,
szCurrentFileName,sizeof(szCurrentFileName)-1,
NULL,0,NULL,0);
if (err == UNZ_OK)
{
if (unzStringFileNameCompare(szCurrentFileName,
szFileName,iCaseSensitivity)==0)
return UNZ_OK;
err = unzGoToNextFile(file);
}
}
/* We failed, so restore the state of the 'current file' to where we
* were.
*/
s->num_file = num_fileSaved ;
s->pos_in_central_dir = pos_in_central_dirSaved ;
s->cur_file_info = cur_file_infoSaved;
s->cur_file_info_internal = cur_file_info_internalSaved;
return err;
}
/*
///////////////////////////////////////////
// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
// I need random access
//
// Further optimization could be realized by adding an ability
// to cache the directory in memory. The goal being a single
// comprehensive file read to put the file I need in a memory.
*/
/*
typedef struct unz_file_pos_s
{
ZPOS64_T pos_in_zip_directory; // offset in file
ZPOS64_T num_of_file; // # of file
} unz_file_pos;
*/
extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos)
{
unz64_s* s;
if (file==NULL || file_pos==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
return UNZ_END_OF_LIST_OF_FILE;
file_pos->pos_in_zip_directory = s->pos_in_central_dir;
file_pos->num_of_file = s->num_file;
return UNZ_OK;
}
extern int ZEXPORT unzGetFilePos(
unzFile file,
unz_file_pos* file_pos)
{
unz64_file_pos file_pos64;
int err = unzGetFilePos64(file,&file_pos64);
if (err==UNZ_OK)
{
file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
file_pos->num_of_file = (uLong)file_pos64.num_of_file;
}
return err;
}
extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos)
{
unz64_s* s;
int err;
if (file==NULL || file_pos==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
/* jump to the right spot */
s->pos_in_central_dir = file_pos->pos_in_zip_directory;
s->num_file = file_pos->num_of_file;
/* set the current file */
err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
/* return results */
s->current_file_ok = (err == UNZ_OK);
return err;
}
extern int ZEXPORT unzGoToFilePos(
unzFile file,
unz_file_pos* file_pos)
{
unz64_file_pos file_pos64;
if (file_pos == NULL)
return UNZ_PARAMERROR;
file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
file_pos64.num_of_file = file_pos->num_of_file;
return unzGoToFilePos64(file,&file_pos64);
}
/* Unzip Helper Functions - should be here? */
/*///////////////////////////////////////// */
/*
Read the local header of the current zipfile
Check the coherency of the local header and info in the end of central
directory about this file
store in *piSizeVar the size of extra info in local header
(filename and size of extra field data)
*/
local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar,
ZPOS64_T * poffset_local_extrafield,
uInt * psize_local_extrafield)
{
uLong uMagic,uData,uFlags;
uLong size_filename;
uLong size_extra_field;
int err=UNZ_OK;
*piSizeVar = 0;
*poffset_local_extrafield = 0;
*psize_local_extrafield = 0;
if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
return UNZ_ERRNO;
if (err==UNZ_OK)
{
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
err=UNZ_ERRNO;
else if (uMagic!=0x04034b50)
err=UNZ_BADZIPFILE;
}
if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
err=UNZ_ERRNO;
/*
else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
err=UNZ_BADZIPFILE;
*/
if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
err=UNZ_ERRNO;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
err=UNZ_ERRNO;
else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
err=UNZ_BADZIPFILE;
if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
(s->cur_file_info.compression_method!=Z_DEFLATED))
err=UNZ_BADZIPFILE;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
err=UNZ_ERRNO;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
err=UNZ_ERRNO;
else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
err=UNZ_BADZIPFILE;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
err=UNZ_ERRNO;
else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))
err=UNZ_BADZIPFILE;
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
err=UNZ_ERRNO;
else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))
err=UNZ_BADZIPFILE;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
err=UNZ_ERRNO;
else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
err=UNZ_BADZIPFILE;
*piSizeVar += (uInt)size_filename;
if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
err=UNZ_ERRNO;
*poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
SIZEZIPLOCALHEADER + size_filename;
*psize_local_extrafield = (uInt)size_extra_field;
*piSizeVar += (uInt)size_extra_field;
return err;
}
/*
Open for reading data the current file in the zipfile.
If there is no error and the file is opened, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method,
int* level, int raw, const char* password)
{
int err=UNZ_OK;
uInt iSizeVar;
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
ZPOS64_T offset_local_extrafield; /* offset of the local extra field */
uInt size_local_extrafield; /* size of the local extra field */
# ifndef NOUNCRYPT
char source[12];
# else
if (password != NULL)
return UNZ_PARAMERROR;
# endif
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
if (!s->current_file_ok)
return UNZ_PARAMERROR;
if (s->pfile_in_zip_read != NULL)
unzCloseCurrentFile(file);
if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
return UNZ_BADZIPFILE;
pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
if (pfile_in_zip_read_info==NULL)
return UNZ_INTERNALERROR;
pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
pfile_in_zip_read_info->pos_local_extrafield=0;
pfile_in_zip_read_info->raw=raw;
if (pfile_in_zip_read_info->read_buffer==NULL)
{
TRYFREE(pfile_in_zip_read_info);
return UNZ_INTERNALERROR;
}
pfile_in_zip_read_info->stream_initialised=0;
if (method!=NULL)
*method = (int)s->cur_file_info.compression_method;
if (level!=NULL)
{
*level = 6;
switch (s->cur_file_info.flag & 0x06)
{
case 6 : *level = 1; break;
case 4 : *level = 2; break;
case 2 : *level = 9; break;
}
}
if ((s->cur_file_info.compression_method!=0) &&
(s->cur_file_info.compression_method!=Z_DEFLATED))
err=UNZ_BADZIPFILE;
pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
pfile_in_zip_read_info->crc32=0;
pfile_in_zip_read_info->total_out_64=0;
pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
pfile_in_zip_read_info->filestream=s->filestream;
pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
pfile_in_zip_read_info->stream.total_out = 0;
if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
{
pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
pfile_in_zip_read_info->stream.zfree = (free_func)0;
pfile_in_zip_read_info->stream.opaque = (voidpf)0;
pfile_in_zip_read_info->stream.next_in = 0;
pfile_in_zip_read_info->stream.avail_in = 0;
err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
if (err == Z_OK)
pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
else
{
TRYFREE(pfile_in_zip_read_info->read_buffer);
TRYFREE(pfile_in_zip_read_info);
return err;
}
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
* In unzip, i don't wait absolutely Z_STREAM_END because I known the
* size of both compressed and uncompressed data
*/
}
pfile_in_zip_read_info->rest_read_compressed =
s->cur_file_info.compressed_size ;
pfile_in_zip_read_info->rest_read_uncompressed =
s->cur_file_info.uncompressed_size ;
pfile_in_zip_read_info->pos_in_zipfile =
s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
iSizeVar;
pfile_in_zip_read_info->stream.avail_in = (uInt)0;
s->pfile_in_zip_read = pfile_in_zip_read_info;
s->encrypted = 0;
# ifndef NOUNCRYPT
if (password != NULL)
{
int i;
s->pcrc_32_tab = get_crc_table();
init_keys(password,s->keys,s->pcrc_32_tab);
if (ZSEEK64(s->z_filefunc, s->filestream,
s->pfile_in_zip_read->pos_in_zipfile +
s->pfile_in_zip_read->byte_before_the_zipfile,
SEEK_SET)!=0)
return UNZ_INTERNALERROR;
if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)
return UNZ_INTERNALERROR;
for (i = 0; i<12; i++)
zdecode(s->keys,s->pcrc_32_tab,source[i]);
s->pfile_in_zip_read->pos_in_zipfile+=12;
s->encrypted=1;
}
# endif
return UNZ_OK;
}
extern int ZEXPORT unzOpenCurrentFile (unzFile file)
{
return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
}
extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password)
{
return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
}
extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw)
{
return unzOpenCurrentFile3(file, method, level, raw, NULL);
}
/** Addition for GDAL : START */
extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file)
{
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
s=(unz64_s*)file;
if (file==NULL)
return 0; /*UNZ_PARAMERROR; */
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return 0; /*UNZ_PARAMERROR; */
return pfile_in_zip_read_info->pos_in_zipfile +
pfile_in_zip_read_info->byte_before_the_zipfile;
}
/** Addition for GDAL : END */
/*
Read bytes from the current file.
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
{
int err=UNZ_OK;
uInt iRead = 0;
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return UNZ_PARAMERROR;
if (pfile_in_zip_read_info->read_buffer == NULL)
return UNZ_END_OF_LIST_OF_FILE;
if (len==0)
return 0;
pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
pfile_in_zip_read_info->stream.avail_out = (uInt)len;
if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
(!(pfile_in_zip_read_info->raw)))
pfile_in_zip_read_info->stream.avail_out =
(uInt)pfile_in_zip_read_info->rest_read_uncompressed;
if ((len>pfile_in_zip_read_info->rest_read_compressed+
pfile_in_zip_read_info->stream.avail_in) &&
(pfile_in_zip_read_info->raw))
pfile_in_zip_read_info->stream.avail_out =
(uInt)pfile_in_zip_read_info->rest_read_compressed+
pfile_in_zip_read_info->stream.avail_in;
while (pfile_in_zip_read_info->stream.avail_out>0)
{
if ((pfile_in_zip_read_info->stream.avail_in==0) &&
(pfile_in_zip_read_info->rest_read_compressed>0))
{
uInt uReadThis = UNZ_BUFSIZE;
if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
if (uReadThis == 0)
return UNZ_EOF;
if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
pfile_in_zip_read_info->filestream,
pfile_in_zip_read_info->pos_in_zipfile +
pfile_in_zip_read_info->byte_before_the_zipfile,
ZLIB_FILEFUNC_SEEK_SET)!=0)
return UNZ_ERRNO;
if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
pfile_in_zip_read_info->filestream,
pfile_in_zip_read_info->read_buffer,
uReadThis)!=uReadThis)
return UNZ_ERRNO;
# ifndef NOUNCRYPT
if(s->encrypted)
{
uInt i;
for(i=0;i<uReadThis;i++)
pfile_in_zip_read_info->read_buffer[i] =
zdecode(s->keys,s->pcrc_32_tab,
pfile_in_zip_read_info->read_buffer[i]);
}
# endif
pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
pfile_in_zip_read_info->stream.next_in =
(Bytef*)pfile_in_zip_read_info->read_buffer;
pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
}
if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
{
uInt uDoCopy,i ;
if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
(pfile_in_zip_read_info->rest_read_compressed == 0))
return (iRead==0) ? UNZ_EOF : iRead;
if (pfile_in_zip_read_info->stream.avail_out <
pfile_in_zip_read_info->stream.avail_in)
uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
else
uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
for (i=0;i<uDoCopy;i++)
*(pfile_in_zip_read_info->stream.next_out+i) =
*(pfile_in_zip_read_info->stream.next_in+i);
pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;
pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
pfile_in_zip_read_info->stream.next_out,
uDoCopy);
pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
pfile_in_zip_read_info->stream.next_out += uDoCopy;
pfile_in_zip_read_info->stream.next_in += uDoCopy;
pfile_in_zip_read_info->stream.total_out += uDoCopy;
iRead += uDoCopy;
}
else
{
uInt uAvailOutBefore,uAvailOutAfter;
const Bytef *bufBefore;
uInt uOutThis;
int flush=Z_SYNC_FLUSH;
uAvailOutBefore = pfile_in_zip_read_info->stream.avail_out;
bufBefore = pfile_in_zip_read_info->stream.next_out;
err=inflate(&pfile_in_zip_read_info->stream,flush);
if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
err = Z_DATA_ERROR;
uAvailOutAfter = pfile_in_zip_read_info->stream.avail_out;
uOutThis = uAvailOutBefore - uAvailOutAfter;
pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
pfile_in_zip_read_info->crc32
= crc32(pfile_in_zip_read_info->crc32,bufBefore, uOutThis);
pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
iRead += uAvailOutBefore - uAvailOutAfter;
if (err==Z_STREAM_END)
return (iRead==0) ? UNZ_EOF : iRead;
if (err!=Z_OK)
break;
}
}
if (err==Z_OK)
return iRead;
return err;
}
/*
Give the current position in uncompressed data
*/
extern z_off_t ZEXPORT unztell (unzFile file)
{
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return UNZ_PARAMERROR;
return (z_off_t)pfile_in_zip_read_info->stream.total_out;
}
extern ZPOS64_T ZEXPORT unztell64 (unzFile file)
{
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return (ZPOS64_T)-1;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return (ZPOS64_T)-1;
return pfile_in_zip_read_info->total_out_64;
}
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzeof (unzFile file)
{
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return UNZ_PARAMERROR;
if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
return 1;
else
return 0;
}
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field that can be read
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len)
{
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
uInt read_now;
ZPOS64_T size_to_read;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return UNZ_PARAMERROR;
size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
pfile_in_zip_read_info->pos_local_extrafield);
if (buf==NULL)
return (int)size_to_read;
if (len>size_to_read)
read_now = (uInt)size_to_read;
else
read_now = (uInt)len ;
if (read_now==0)
return 0;
if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
pfile_in_zip_read_info->filestream,
pfile_in_zip_read_info->offset_local_extrafield +
pfile_in_zip_read_info->pos_local_extrafield,
ZLIB_FILEFUNC_SEEK_SET)!=0)
return UNZ_ERRNO;
if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
pfile_in_zip_read_info->filestream,
buf,read_now)!=read_now)
return UNZ_ERRNO;
return (int)read_now;
}
/*
Close the file in zip opened with unzipOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzCloseCurrentFile (unzFile file)
{
int err=UNZ_OK;
unz64_s* s;
file_in_zip64_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
pfile_in_zip_read_info=s->pfile_in_zip_read;
if (pfile_in_zip_read_info==NULL)
return UNZ_PARAMERROR;
if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
(!pfile_in_zip_read_info->raw))
{
if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
err=UNZ_CRCERROR;
}
TRYFREE(pfile_in_zip_read_info->read_buffer);
pfile_in_zip_read_info->read_buffer = NULL;
if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
inflateEnd(&pfile_in_zip_read_info->stream);
pfile_in_zip_read_info->stream_initialised = 0;
TRYFREE(pfile_in_zip_read_info);
s->pfile_in_zip_read=NULL;
return err;
}
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf)
{
unz64_s* s;
uLong uReadThis ;
if (file==NULL)
return (int)UNZ_PARAMERROR;
s=(unz64_s*)file;
uReadThis = uSizeBuf;
if (uReadThis>s->gi.size_comment)
uReadThis = s->gi.size_comment;
if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
return UNZ_ERRNO;
if (uReadThis>0)
{
*szComment='\0';
if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
return UNZ_ERRNO;
}
if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
*(szComment+s->gi.size_comment)='\0';
return (int)uReadThis;
}
/* Additions by RX '2004 */
extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file)
{
unz64_s* s;
if (file==NULL)
return 0; /*UNZ_PARAMERROR; */
s=(unz64_s*)file;
if (!s->current_file_ok)
return 0;
if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
if (s->num_file==s->gi.number_entry)
return 0;
return s->pos_in_central_dir;
}
extern uLong ZEXPORT unzGetOffset (unzFile file)
{
ZPOS64_T offset64;
if (file==NULL)
return 0; /*UNZ_PARAMERROR; */
offset64 = unzGetOffset64(file);
return (uLong)offset64;
}
extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos)
{
unz64_s* s;
int err;
if (file==NULL)
return UNZ_PARAMERROR;
s=(unz64_s*)file;
s->pos_in_central_dir = pos;
s->num_file = s->gi.number_entry; /* hack */
err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
&s->cur_file_info_internal,
NULL,0,NULL,0,NULL,0);
s->current_file_ok = (err == UNZ_OK);
return err;
}
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos)
{
return unzSetOffset64(file,pos);
}
int ZEXPORT unzSetFlags(unzFile file, unsigned flags)
{
unz64_s* s;
if (file == NULL)
return UNZ_PARAMERROR;
s = (unz64_s*)file;
s->flags |= flags;
return UNZ_OK;
}
int ZEXPORT unzClearFlags(unzFile file, unsigned flags)
{
unz64_s* s;
if (file == NULL)
return UNZ_PARAMERROR;
s = (unz64_s*)file;
s->flags &= ~flags;
return UNZ_OK;
}
diff --git a/quazip/unzip.h b/quazip/unzip.h
--- a/quazip/unzip.h
+++ b/quazip/unzip.h
@@ -1,452 +1,455 @@
/* unzip.h -- IO for uncompress .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications of Unzip for Zip64
Copyright (C) 2007-2008 Even Rouault
Modifications for Zip64 support on both zip and unzip
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
---------------------------------------------------------------------------------
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
---------------------------------------------------------------------------------
Changes
See header of unzip64.c
---------------------------------------------------------------------------
As per the requirement above, this file is plainly marked as modified
by Sergey A. Tachenov. Most modifications include the I/O API redesign
to support QIODevice interface. Some improvements and small fixes were also made.
*/
#ifndef _unz64_H
#define _unz64_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _ZLIB_H
-#include "zlib.h"
+#include <zlib.h>
#endif
#ifndef _ZLIBIOAPI_H
#include "ioapi.h"
#endif
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unzFile__;
typedef unzFile__ *unzFile;
#else
typedef voidp unzFile;
#endif
#define UNZ_OK (0)
#define UNZ_END_OF_LIST_OF_FILE (-100)
#define UNZ_ERRNO (Z_ERRNO)
#define UNZ_EOF (0)
#define UNZ_PARAMERROR (-102)
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
#define UNZ_AUTO_CLOSE 0x01u
#define UNZ_DEFAULT_FLAGS UNZ_AUTO_CLOSE
+#define UNZ_ENCODING_UTF8 0x0800u
/* tm_unz contain date/time info */
typedef struct tm_unz_s
{
uInt tm_sec; /* seconds after the minute - [0,59] */
uInt tm_min; /* minutes after the hour - [0,59] */
uInt tm_hour; /* hours since midnight - [0,23] */
uInt tm_mday; /* day of the month - [1,31] */
uInt tm_mon; /* months since January - [0,11] */
uInt tm_year; /* years - [1980..2044] */
} tm_unz;
/* unz_global_info structure contain global data about the ZIPfile
These data comes from the end of central dir */
typedef struct unz_global_info64_s
{
ZPOS64_T number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info64;
typedef struct unz_global_info_s
{
uLong number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info;
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_info64_s
{
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
ZPOS64_T compressed_size; /* compressed size 8 bytes */
ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info64;
typedef struct unz_file_info_s
{
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
uLong compressed_size; /* compressed size 4 bytes */
uLong uncompressed_size; /* uncompressed size 4 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info;
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
const char* fileName2,
int iCaseSensitivity));
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern unzFile ZEXPORT unzOpen OF((voidpf file));
extern unzFile ZEXPORT unzOpen64 OF((voidpf file));
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
"zlib/zlib113.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
the "64" function take a const void* pointer, because the path is just the
value passed to the open64_file_func callback.
Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
does not describe the reality
*/
extern unzFile ZEXPORT unzOpen2 OF((voidpf file,
zlib_filefunc_def* pzlib_filefunc_def));
/*
Open a Zip file, like unzOpen, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
extern unzFile ZEXPORT unzOpen2_64 OF((voidpf file,
zlib_filefunc64_def* pzlib_filefunc_def));
/*
Open a Zip file, like unz64Open, but provide a set of file low level API
for read/write the zip file (see ioapi.h)
*/
/*
* Exported by Sergey A. Tachenov to implement some QuaZIP features. This
* function MAY change signature in order to implement even more features.
* You have been warned!
* */
extern unzFile unzOpenInternal (voidpf file,
zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
int is64bitOpenFunction, unsigned flags);
extern int ZEXPORT unzClose OF((unzFile file));
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
unz_global_info *pglobal_info));
extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
unz_global_info64 *pglobal_info));
+
+extern int ZEXPORT unzGetFileFlags OF((unzFile file, unsigned* pflags));
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
char *szComment,
uLong uSizeBuf));
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
/***************************************************************************/
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzLocateFile OF((unzFile file,
const char *szFileName,
int iCaseSensitivity));
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
/* ****************************************** */
/* Ryan supplied functions */
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_pos_s
{
uLong pos_in_zip_directory; /* offset in zip file directory */
uLong num_of_file; /* # of file */
} unz_file_pos;
extern int ZEXPORT unzGetFilePos(
unzFile file,
unz_file_pos* file_pos);
extern int ZEXPORT unzGoToFilePos(
unzFile file,
unz_file_pos* file_pos);
typedef struct unz64_file_pos_s
{
ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
ZPOS64_T num_of_file; /* # of file */
} unz64_file_pos;
extern int ZEXPORT unzGetFilePos64(
unzFile file,
unz64_file_pos* file_pos);
extern int ZEXPORT unzGoToFilePos64(
unzFile file,
const unz64_file_pos* file_pos);
/* ****************************************** */
extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
unz_file_info64 *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
the current file
if szFileName!=NULL, the filemane string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
This is the Central-header version of the extra field
if szComment!=NULL, the comment string of the file will be copied in szComment
(commentBufferSize is the size of the buffer)
*/
/** Addition for GDAL : START */
extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
/** Addition for GDAL : END */
/***************************************************************************/
/* for reading the content of the current zipfile, you can open it, read data
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
const char* password));
/*
Open for reading data the current file in the zipfile.
password is a crypting password
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
int* method,
int* level,
int raw));
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
*method will receive method of compression, *level will receive level of
compression
note : you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
int* method,
int* level,
int raw,
const char* password));
/*
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
if raw==1
*method will receive method of compression, *level will receive level of
compression
note : you can set level parameter as NULL (if you did not want known level,
but you CANNOT set method parameter as NULL
*/
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
voidp buf,
unsigned len));
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell OF((unzFile file));
extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof OF((unzFile file));
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
voidp buf,
unsigned len));
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
/***************************************************************************/
/* Get the current file offset */
extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
extern uLong ZEXPORT unzGetOffset (unzFile file);
/* Set the current file offset */
extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
extern int ZEXPORT unzSetFlags(unzFile file, unsigned flags);
extern int ZEXPORT unzClearFlags(unzFile file, unsigned flags);
#ifdef __cplusplus
}
#endif
#endif /* _unz64_H */
diff --git a/quazip/zip.c b/quazip/zip.c
--- a/quazip/zip.c
+++ b/quazip/zip.c
@@ -1,1996 +1,2000 @@
/* zip.c -- IO on .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
Modifications for QIODevice support and other QuaZIP fixes
Copyright (C) 2005-2014 Sergey A. Tachenov
Fixing static code analysis issues
Copyright (C) 2016 Intel Deutschland GmbH
Changes
Oct-2009 - Mathias Svensson - Remove old C style function prototypes
Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
It is used when recreting zip archive with RAW when deleting items from a zip.
ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed.
Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include "zlib.h"
+
+#include <zlib.h>
#if (ZLIB_VERNUM < 0x1270)
typedef uLongf z_crc_t;
#endif
#include "zip.h"
#ifdef STDC
# include <stddef.h>
# include <string.h>
# include <stdlib.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
#ifndef VERSIONMADEBY
# define VERSIONMADEBY (0x031e) /* best for standard pkware crypt */
#endif
#ifndef Z_BUFSIZE
#define Z_BUFSIZE (64*1024) /* (16384) */
#endif
#ifndef Z_MAXFILENAMEINZIP
#define Z_MAXFILENAMEINZIP (256)
#endif
#ifndef ALLOC
# define ALLOC(size) (malloc(size))
#endif
#ifndef TRYFREE
# define TRYFREE(p) {if (p) free(p);}
#endif
/*
#define SIZECENTRALDIRITEM (0x2e)
#define SIZEZIPLOCALHEADER (0x1e)
*/
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
/* NOT sure that this work on ALL platform */
#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef DEF_MEM_LEVEL
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
#endif
const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
#define SIZEDATA_INDATABLOCK (4096-(4*4))
#define LOCALHEADERMAGIC (0x04034b50)
#define DESCRIPTORHEADERMAGIC (0x08074b50)
#define CENTRALHEADERMAGIC (0x02014b50)
#define ENDHEADERMAGIC (0x06054b50)
#define ZIP64ENDHEADERMAGIC (0x6064b50)
#define ZIP64ENDLOCHEADERMAGIC (0x7064b50)
#define FLAG_LOCALHEADER_OFFSET (0x06)
#define CRC_LOCALHEADER_OFFSET (0x0e)
#define SIZECENTRALHEADER (0x2e) /* 46 */
typedef struct linkedlist_datablock_internal_s
{
struct linkedlist_datablock_internal_s* next_datablock;
uLong avail_in_this_block;
uLong filled_in_this_block;
uLong unused; /* for future use and alignement */
unsigned char data[SIZEDATA_INDATABLOCK];
} linkedlist_datablock_internal;
typedef struct linkedlist_data_s
{
linkedlist_datablock_internal* first_block;
linkedlist_datablock_internal* last_block;
} linkedlist_data;
typedef struct
{
z_stream stream; /* zLib stream structure for inflate */
int stream_initialised; /* 1 is stream is initialised */
uInt pos_in_buffered_data; /* last written byte in buffered_data */
ZPOS64_T pos_local_header; /* offset of the local header of the file
currenty writing */
char* central_header; /* central header data for the current file */
uLong size_centralExtra;
uLong size_centralheader; /* size of the central header for cur file */
uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */
uLong flag; /* flag of the file currently writing */
int method; /* compression method of file currenty wr.*/
int raw; /* 1 for directly writing raw data */
Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
uLong dosDate;
uLong crc32;
int encrypt;
int zip64; /* Add ZIP64 extened information in the extra field */
ZPOS64_T pos_zip64extrainfo;
ZPOS64_T totalCompressedData;
ZPOS64_T totalUncompressedData;
#ifndef NOCRYPT
unsigned long keys[3]; /* keys defining the pseudo-random sequence */
const z_crc_t FAR * pcrc_32_tab;
int crypt_header_size;
#endif
} curfile64_info;
typedef struct
{
zlib_filefunc64_32_def z_filefunc;
voidpf filestream; /* io structore of the zipfile */
linkedlist_data central_dir;/* datablock with central dir in construction*/
int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
curfile64_info ci; /* info on the file curretly writing */
ZPOS64_T begin_pos; /* position of the beginning of the zipfile */
ZPOS64_T add_position_when_writting_offset;
ZPOS64_T number_entry;
#ifndef NO_ADDFILEINEXISTINGZIP
char *globalcomment;
#endif
unsigned flags;
} zip64_internal;
#ifndef NOCRYPT
#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
#include "minizip_crypt.h"
#endif
local linkedlist_datablock_internal* allocate_new_datablock()
{
linkedlist_datablock_internal* ldi;
ldi = (linkedlist_datablock_internal*)
ALLOC(sizeof(linkedlist_datablock_internal));
if (ldi!=NULL)
{
ldi->next_datablock = NULL ;
ldi->filled_in_this_block = 0 ;
ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
}
return ldi;
}
local void free_datablock(linkedlist_datablock_internal* ldi)
{
while (ldi!=NULL)
{
linkedlist_datablock_internal* ldinext = ldi->next_datablock;
TRYFREE(ldi);
ldi = ldinext;
}
}
local void init_linkedlist(linkedlist_data* ll)
{
ll->first_block = ll->last_block = NULL;
}
local void free_linkedlist(linkedlist_data* ll)
{
free_datablock(ll->first_block);
ll->first_block = ll->last_block = NULL;
}
local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len)
{
linkedlist_datablock_internal* ldi;
const unsigned char* from_copy;
if (ll==NULL)
return ZIP_INTERNALERROR;
if (ll->last_block == NULL)
{
ll->first_block = ll->last_block = allocate_new_datablock();
if (ll->first_block == NULL)
return ZIP_INTERNALERROR;
}
ldi = ll->last_block;
from_copy = (unsigned char*)buf;
while (len>0)
{
uInt copy_this;
uInt i;
unsigned char* to_copy;
if (ldi->avail_in_this_block==0)
{
ldi->next_datablock = allocate_new_datablock();
if (ldi->next_datablock == NULL)
return ZIP_INTERNALERROR;
ldi = ldi->next_datablock ;
ll->last_block = ldi;
}
if (ldi->avail_in_this_block < len)
copy_this = (uInt)ldi->avail_in_this_block;
else
copy_this = (uInt)len;
to_copy = &(ldi->data[ldi->filled_in_this_block]);
for (i=0;i<copy_this;i++)
*(to_copy+i)=*(from_copy+i);
ldi->filled_in_this_block += copy_this;
ldi->avail_in_this_block -= copy_this;
from_copy += copy_this ;
len -= copy_this;
}
return ZIP_OK;
}
/****************************************************************************/
#ifndef NO_ADDFILEINEXISTINGZIP
/* ===========================================================================
Inputs a long in LSB order to the given file
nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
*/
local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte));
local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)
{
unsigned char buf[8];
int n;
for (n = 0; n < nbByte; n++)
{
buf[n] = (unsigned char)(x & 0xff);
x >>= 8;
}
if (x != 0)
{ /* data overflow - hack for ZIP64 (X Roche) */
for (n = 0; n < nbByte; n++)
{
buf[n] = 0xff;
}
}
if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
return ZIP_ERRNO;
else
return ZIP_OK;
}
local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte));
local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte)
{
unsigned char* buf=(unsigned char*)dest;
int n;
for (n = 0; n < nbByte; n++) {
buf[n] = (unsigned char)(x & 0xff);
x >>= 8;
}
if (x != 0)
{ /* data overflow - hack for ZIP64 */
for (n = 0; n < nbByte; n++)
{
buf[n] = 0xff;
}
}
}
/****************************************************************************/
local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm)
{
uLong year = (uLong)ptm->tm_year;
if (year>=1980)
year-=1980;
else if (year>=80)
year-=80;
return
(uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
}
/****************************************************************************/
local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));
local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi)
{
unsigned char c;
int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
if (err==1)
{
*pi = (int)c;
return ZIP_OK;
}
else
{
if (ZERROR64(*pzlib_filefunc_def,filestream))
return ZIP_ERRNO;
else
return ZIP_EOF;
}
}
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
{
uLong x ;
int i = 0;
int err;
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (uLong)i;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((uLong)i)<<8;
if (err==ZIP_OK)
*pX = x;
else
*pX = 0;
return err;
}
local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
{
uLong x ;
int i = 0;
int err;
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (uLong)i;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((uLong)i)<<8;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((uLong)i)<<16;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((uLong)i)<<24;
if (err==ZIP_OK)
*pX = x;
else
*pX = 0;
return err;
}
local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));
local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)
{
ZPOS64_T x;
int i = 0;
int err;
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x = (ZPOS64_T)i;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<8;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<16;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<24;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<32;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<40;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<48;
if (err==ZIP_OK)
err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
x += ((ZPOS64_T)i)<<56;
if (err==ZIP_OK)
*pX = x;
else
*pX = 0;
return err;
}
#ifndef BUFREADCOMMENT
#define BUFREADCOMMENT (0x400)
#endif
/*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
{
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=0;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
return 0;
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
return 0;
uBackRead = 4;
while (uBackRead<uMaxBack)
{
uLong uReadSize;
ZPOS64_T uReadPos ;
int i;
if (uBackRead+BUFREADCOMMENT>uMaxBack)
uBackRead = uMaxBack;
else
uBackRead+=BUFREADCOMMENT;
uReadPos = uSizeFile-uBackRead ;
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
(BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
break;
if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
break;
for (i=(int)uReadSize-3; (i--)>0;){
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
{
uPosFound = uReadPos+i;
break;
}
}
if (uPosFound!=0)
break;
}
TRYFREE(buf);
return uPosFound;
}
/*
Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
the global comment)
*/
local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
{
unsigned char* buf;
ZPOS64_T uSizeFile;
ZPOS64_T uBackRead;
ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
ZPOS64_T uPosFound=0;
uLong uL;
ZPOS64_T relativeOffset;
if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
return 0;
uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
if (buf==NULL)
return 0;
uBackRead = 4;
while (uBackRead<uMaxBack)
{
uLong uReadSize;
ZPOS64_T uReadPos;
int i;
if (uBackRead+BUFREADCOMMENT>uMaxBack)
uBackRead = uMaxBack;
else
uBackRead+=BUFREADCOMMENT;
uReadPos = uSizeFile-uBackRead ;
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
(BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
break;
if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
break;
for (i=(int)uReadSize-3; (i--)>0;)
{
/* Signature "0x07064b50" Zip64 end of central directory locater */
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
{
uPosFound = uReadPos+i;
break;
}
}
if (uPosFound!=0)
break;
}
TRYFREE(buf);
if (uPosFound == 0)
return 0;
/* Zip64 end of central directory locator */
if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
return 0;
/* the signature, already checked */
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
return 0;
/* number of the disk with the start of the zip64 end of central directory */
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
return 0;
if (uL != 0)
return 0;
/* relative offset of the zip64 end of central directory record */
if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK)
return 0;
/* total number of disks */
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
return 0;
if (uL != 1)
return 0;
/* Goto Zip64 end of central directory record */
if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
return 0;
/* the signature */
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
return 0;
if (uL != 0x06064b50) /* signature of 'Zip64 end of central directory' */
return 0;
return relativeOffset;
}
int LoadCentralDirectoryRecord(zip64_internal* pziinit)
{
int err=ZIP_OK;
ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
ZPOS64_T size_central_dir; /* size of the central directory */
ZPOS64_T offset_central_dir; /* offset of start of central directory */
ZPOS64_T central_pos;
uLong uL;
uLong number_disk; /* number of the current dist, used for
spaning ZIP, unsupported, always 0*/
uLong number_disk_with_CD; /* number the the disk with central dir, used
for spaning ZIP, unsupported, always 0*/
ZPOS64_T number_entry;
ZPOS64_T number_entry_CD; /* total number of entries in
the central dir
(same than number_entry on nospan) */
uLong VersionMadeBy;
uLong VersionNeeded;
uLong size_comment;
int hasZIP64Record = 0;
/* check first if we find a ZIP64 record */
central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);
if(central_pos > 0)
{
hasZIP64Record = 1;
}
else if(central_pos == 0)
{
central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream);
}
/* disable to allow appending to empty ZIP archive
if (central_pos==0)
err=ZIP_ERRNO;
*/
if(hasZIP64Record)
{
ZPOS64_T sizeEndOfCentralDirectory;
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
err=ZIP_ERRNO;
/* the signature, already checked */
if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
err=ZIP_ERRNO;
/* size of zip64 end of central directory record */
if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)
err=ZIP_ERRNO;
/* version made by */
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK)
err=ZIP_ERRNO;
/* version needed to extract */
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK)
err=ZIP_ERRNO;
/* number of this disk */
if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
err=ZIP_ERRNO;
/* number of the disk with the start of the central directory */
if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
err=ZIP_ERRNO;
/* total number of entries in the central directory on this disk */
if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK)
err=ZIP_ERRNO;
/* total number of entries in the central directory */
if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK)
err=ZIP_ERRNO;
if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
err=ZIP_BADZIPFILE;
/* size of the central directory */
if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK)
err=ZIP_ERRNO;
/* offset of start of central directory with respect to the
starting disk number */
if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)
err=ZIP_ERRNO;
/* TODO.. */
/* read the comment from the standard central header. */
size_comment = 0;
}
else
{
/* Read End of central Directory info */
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
err=ZIP_ERRNO;
/* the signature, already checked */
if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
err=ZIP_ERRNO;
/* number of this disk */
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
err=ZIP_ERRNO;
/* number of the disk with the start of the central directory */
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
err=ZIP_ERRNO;
/* total number of entries in the central dir on this disk */
number_entry = 0;
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
err=ZIP_ERRNO;
else
number_entry = uL;
/* total number of entries in the central dir */
number_entry_CD = 0;
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
err=ZIP_ERRNO;
else
number_entry_CD = uL;
if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
err=ZIP_BADZIPFILE;
/* size of the central directory */
size_central_dir = 0;
if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
err=ZIP_ERRNO;
else
size_central_dir = uL;
/* offset of start of central directory with respect to the starting disk number */
offset_central_dir = 0;
if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
err=ZIP_ERRNO;
else
offset_central_dir = uL;
/* zipfile global comment length */
if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK)
err=ZIP_ERRNO;
}
if ((central_pos<offset_central_dir+size_central_dir) &&
(err==ZIP_OK))
err=ZIP_BADZIPFILE;
if (err!=ZIP_OK)
{
if ((pziinit->flags & ZIP_AUTO_CLOSE) != 0) {
ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);
} else {
ZFAKECLOSE64(pziinit->z_filefunc, pziinit->filestream);
}
return ZIP_ERRNO;
}
if (size_comment>0)
{
pziinit->globalcomment = (char*)ALLOC(size_comment+1);
if (pziinit->globalcomment)
{
size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);
pziinit->globalcomment[size_comment]=0;
}
}
byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);
pziinit->add_position_when_writting_offset = byte_before_the_zipfile;
{
ZPOS64_T size_central_dir_to_read = size_central_dir;
size_t buf_size = SIZEDATA_INDATABLOCK;
void* buf_read = (void*)ALLOC(buf_size);
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
err=ZIP_ERRNO;
while ((size_central_dir_to_read>0) && (err==ZIP_OK))
{
ZPOS64_T read_this = SIZEDATA_INDATABLOCK;
if (read_this > size_central_dir_to_read)
read_this = size_central_dir_to_read;
if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this)
err=ZIP_ERRNO;
if (err==ZIP_OK)
err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);
size_central_dir_to_read-=read_this;
}
TRYFREE(buf_read);
}
pziinit->begin_pos = byte_before_the_zipfile;
pziinit->number_entry = number_entry_CD;
if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
err=ZIP_ERRNO;
return err;
}
#endif /* !NO_ADDFILEINEXISTINGZIP*/
/************************************************************/
extern zipFile ZEXPORT zipOpen3 (voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
unsigned flags)
{
zip64_internal ziinit;
zip64_internal* zi;
int err=ZIP_OK;
ziinit.flags = flags;
ziinit.z_filefunc.zseek32_file = NULL;
ziinit.z_filefunc.ztell32_file = NULL;
if (pzlib_filefunc64_32_def==NULL)
fill_qiodevice64_filefunc(&ziinit.z_filefunc.zfile_func64);
else
ziinit.z_filefunc = *pzlib_filefunc64_32_def;
ziinit.filestream = ZOPEN64(ziinit.z_filefunc,
file,
(append == APPEND_STATUS_CREATE) ?
(ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
(ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
if (ziinit.filestream == NULL)
return NULL;
if (append == APPEND_STATUS_CREATEAFTER)
ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream);
ziinit.in_opened_file_inzip = 0;
ziinit.ci.stream_initialised = 0;
ziinit.number_entry = 0;
ziinit.add_position_when_writting_offset = 0;
init_linkedlist(&(ziinit.central_dir));
zi = (zip64_internal*)ALLOC(sizeof(zip64_internal));
if (zi==NULL)
{
if ((ziinit.flags & ZIP_AUTO_CLOSE) != 0) {
ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);
} else {
ZFAKECLOSE64(ziinit.z_filefunc,ziinit.filestream);
}
return NULL;
}
/* now we add file in a zipfile */
# ifndef NO_ADDFILEINEXISTINGZIP
ziinit.globalcomment = NULL;
if (append == APPEND_STATUS_ADDINZIP)
{
/* Read and Cache Central Directory Records */
err = LoadCentralDirectoryRecord(&ziinit);
}
if (globalcomment)
{
*globalcomment = ziinit.globalcomment;
}
# endif /* !NO_ADDFILEINEXISTINGZIP*/
if (err != ZIP_OK)
{
# ifndef NO_ADDFILEINEXISTINGZIP
TRYFREE(ziinit.globalcomment);
# endif /* !NO_ADDFILEINEXISTINGZIP*/
TRYFREE(zi);
return NULL;
}
else
{
*zi = ziinit;
return (zipFile)zi;
}
}
extern zipFile ZEXPORT zipOpen2 (voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def)
{
if (pzlib_filefunc32_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
return zipOpen3(file, append, globalcomment, &zlib_filefunc64_32_def_fill, ZIP_DEFAULT_FLAGS);
}
else
return zipOpen3(file, append, globalcomment, NULL, ZIP_DEFAULT_FLAGS);
}
extern zipFile ZEXPORT zipOpen2_64 (voidpf file, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
{
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
zlib_filefunc64_32_def_fill.ztell32_file = NULL;
zlib_filefunc64_32_def_fill.zseek32_file = NULL;
return zipOpen3(file, append, globalcomment, &zlib_filefunc64_32_def_fill, ZIP_DEFAULT_FLAGS);
}
else
return zipOpen3(file, append, globalcomment, NULL, ZIP_DEFAULT_FLAGS);
}
extern zipFile ZEXPORT zipOpen (voidpf file, int append)
{
return zipOpen3(file,append,NULL,NULL, ZIP_DEFAULT_FLAGS);
}
extern zipFile ZEXPORT zipOpen64 (voidpf file, int append)
{
return zipOpen3(file,append,NULL,NULL, ZIP_DEFAULT_FLAGS);
}
int Write_LocalFileHeader(zip64_internal* zi, const char* filename,
uInt size_extrafield_local,
const void* extrafield_local,
uLong version_to_extract)
{
/* write the local header */
int err;
uInt size_filename = (uInt)strlen(filename);
uInt size_extrafield = size_extrafield_local;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4);
if (err==ZIP_OK)
{
- if(zi->ci.zip64)
+ if(zi->ci.flag & ZIP_ENCODING_UTF8)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)63,2);/* Version 6.3 is required for Unicode support */
+ else if(zi->ci.zip64)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)version_to_extract,2);
}
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
/* CRC / Compressed size / Uncompressed size will be filled in later and rewritten later */
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
if (err==ZIP_OK)
{
if(zi->ci.zip64)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
}
if (err==ZIP_OK)
{
if(zi->ci.zip64)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
}
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
if(zi->ci.zip64)
{
size_extrafield += 20;
}
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2);
if ((err==ZIP_OK) && (size_filename > 0))
{
if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
err = ZIP_ERRNO;
}
if ((err==ZIP_OK) && (size_extrafield_local > 0))
{
if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)
err = ZIP_ERRNO;
}
if ((err==ZIP_OK) && (zi->ci.zip64))
{
/* write the Zip64 extended info */
short HeaderID = 1;
short DataSize = 16;
ZPOS64_T CompressedSize = 0;
ZPOS64_T UncompressedSize = 0;
/* Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) */
zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream);
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2);
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2);
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8);
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8);
}
return err;
}
/*
NOTE.
When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
before calling this function it can be done with zipRemoveExtraInfoBlock
It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize
unnecessary allocations.
*/
extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting,
uLong versionMadeBy, uLong flagBase, int zip64)
{
zip64_internal* zi;
uInt size_filename;
uInt size_comment;
uInt i;
int err = ZIP_OK;
uLong version_to_extract;
# ifdef NOCRYPT
if (password != NULL)
return ZIP_PARAMERROR;
# endif
if (file == NULL)
return ZIP_PARAMERROR;
if ((method!=0) && (method!=Z_DEFLATED))
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
if (zi->in_opened_file_inzip == 1)
{
err = zipCloseFileInZip (file);
if (err != ZIP_OK)
return err;
}
if (method == 0
&& (level == 0 || (zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) == 0)
&& (zi->flags & ZIP_SEQUENTIAL) == 0)
{
version_to_extract = 10;
}
else
{
version_to_extract = 20;
}
if (filename==NULL)
filename="-";
if (comment==NULL)
size_comment = 0;
else
size_comment = (uInt)strlen(comment);
size_filename = (uInt)strlen(filename);
if (zipfi == NULL)
zi->ci.dosDate = 0;
else
{
if (zipfi->dosDate != 0)
zi->ci.dosDate = zipfi->dosDate;
else
zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);
}
zi->ci.flag = flagBase;
+ if (zi->flags & ZIP_ENCODING_UTF8)
+ zi->ci.flag |= ZIP_ENCODING_UTF8;
if ((level==8) || (level==9))
zi->ci.flag |= 2;
if (level==2)
zi->ci.flag |= 4;
if (level==1)
zi->ci.flag |= 6;
if (password != NULL)
zi->ci.flag |= 1;
if (version_to_extract >= 20
&& ((zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) != 0
|| (zi->flags & ZIP_SEQUENTIAL) != 0))
zi->ci.flag |= 8;
zi->ci.crc32 = 0;
zi->ci.method = method;
zi->ci.encrypt = 0;
zi->ci.stream_initialised = 0;
zi->ci.pos_in_buffered_data = 0;
zi->ci.raw = raw;
zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);
zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;
zi->ci.size_centralExtraFree = 32; /* Extra space we have reserved in case we need to add ZIP64 extra info data */
zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);
if(!zi->ci.central_header) {
return (Z_MEM_ERROR);
}
zi->ci.size_centralExtra = size_extrafield_global;
zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
/* version info */
zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2);
zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)version_to_extract,2);
zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
if (zipfi==NULL)
zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
else
zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
if (zipfi==NULL)
zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
else
zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
if(zi->ci.pos_local_header >= 0xffffffff)
zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4);
else
zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4);
for (i=0;i<size_filename;i++)
*(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
for (i=0;i<size_extrafield_global;i++)
*(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
*(((const char*)extrafield_global)+i);
for (i=0;i<size_comment;i++)
*(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
size_extrafield_global+i) = *(comment+i);
if (zi->ci.central_header == NULL)
return ZIP_INTERNALERROR;
zi->ci.zip64 = zip64;
zi->ci.totalCompressedData = 0;
zi->ci.totalUncompressedData = 0;
zi->ci.pos_zip64extrainfo = 0;
err = Write_LocalFileHeader(zi, filename, size_extrafield_local,
extrafield_local, version_to_extract);
zi->ci.stream.avail_in = (uInt)0;
zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
zi->ci.stream.next_out = zi->ci.buffered_data;
zi->ci.stream.total_in = 0;
zi->ci.stream.total_out = 0;
zi->ci.stream.data_type = Z_BINARY;
if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
{
if(zi->ci.method == Z_DEFLATED)
{
zi->ci.stream.zalloc = (alloc_func)0;
zi->ci.stream.zfree = (free_func)0;
zi->ci.stream.opaque = (voidpf)0;
if (windowBits>0)
windowBits = -windowBits;
err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
if (err==Z_OK)
zi->ci.stream_initialised = Z_DEFLATED;
}
}
# ifndef NOCRYPT
zi->ci.crypt_header_size = 0;
if ((err==Z_OK) && (password != NULL))
{
unsigned char bufHead[RAND_HEAD_LEN];
unsigned int sizeHead;
zi->ci.encrypt = 1;
zi->ci.pcrc_32_tab = get_crc_table();
/*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
if (crcForCrypting == 0) {
crcForCrypting = (uLong)zi->ci.dosDate << 16; /* ATTANTION! Without this row, you don't unpack your password protected archive in other app. */
}
sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
zi->ci.crypt_header_size = sizeHead;
if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
err = ZIP_ERRNO;
}
# endif
if (err==Z_OK)
zi->in_opened_file_inzip = 1;
return err;
}
extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting,
uLong versionMadeBy, uLong flagBase)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
windowBits, memLevel, strategy,
password, crcForCrypting, versionMadeBy, flagBase, 0);
}
extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
windowBits, memLevel, strategy,
password, crcForCrypting, VERSIONMADEBY, 0, 0);
}
extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw,
int windowBits,int memLevel, int strategy,
const char* password, uLong crcForCrypting, int zip64)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
windowBits, memLevel, strategy,
password, crcForCrypting, VERSIONMADEBY, 0, zip64);
}
extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, 0);
}
extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void* extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int raw, int zip64)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, raw,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, zip64);
}
extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void*extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level, int zip64)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, 0,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, zip64);
}
extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi,
const void* extrafield_local, uInt size_extrafield_local,
const void*extrafield_global, uInt size_extrafield_global,
const char* comment, int method, int level)
{
return zipOpenNewFileInZip4_64 (file, filename, zipfi,
extrafield_local, size_extrafield_local,
extrafield_global, size_extrafield_global,
comment, method, level, 0,
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
NULL, 0, VERSIONMADEBY, 0, 0);
}
local int zip64FlushWriteBuffer(zip64_internal* zi)
{
int err=ZIP_OK;
if (zi->ci.encrypt != 0)
{
#ifndef NOCRYPT
uInt i;
int t;
for (i=0;i<zi->ci.pos_in_buffered_data;i++)
zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t);
#endif
}
if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)
err = ZIP_ERRNO;
zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
zi->ci.totalUncompressedData += zi->ci.stream.total_in;
zi->ci.stream.total_in = 0;
zi->ci.pos_in_buffered_data = 0;
return err;
}
extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len)
{
zip64_internal* zi;
int err=ZIP_OK;
if (file == NULL)
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
if (zi->in_opened_file_inzip == 0)
return ZIP_PARAMERROR;
zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
zi->ci.stream.next_in = (Bytef*)buf;
zi->ci.stream.avail_in = len;
while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
{
if (zi->ci.stream.avail_out == 0)
{
if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
err = ZIP_ERRNO;
zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
zi->ci.stream.next_out = zi->ci.buffered_data;
}
if(err != ZIP_OK)
break;
if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
{
uInt uAvailOutBefore = zi->ci.stream.avail_out;
err=deflate(&zi->ci.stream, Z_NO_FLUSH);
zi->ci.pos_in_buffered_data += uAvailOutBefore - zi->ci.stream.avail_out;
}
else
{
uInt copy_this,i;
if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
copy_this = zi->ci.stream.avail_in;
else
copy_this = zi->ci.stream.avail_out;
for (i = 0; i < copy_this; i++)
*(((char*)zi->ci.stream.next_out)+i) =
*(((const char*)zi->ci.stream.next_in)+i);
{
zi->ci.stream.avail_in -= copy_this;
zi->ci.stream.avail_out-= copy_this;
zi->ci.stream.next_in+= copy_this;
zi->ci.stream.next_out+= copy_this;
zi->ci.stream.total_in+= copy_this;
zi->ci.stream.total_out+= copy_this;
zi->ci.pos_in_buffered_data += copy_this;
}
}
}/* while(...) */
return err;
}
extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32)
{
return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32);
}
extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32)
{
zip64_internal* zi;
ZPOS64_T compressed_size;
uLong invalidValue = 0xffffffff;
short datasize = 0;
int err=ZIP_OK;
if (file == NULL)
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
if (zi->in_opened_file_inzip == 0)
return ZIP_PARAMERROR;
zi->ci.stream.avail_in = 0;
if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
{
while (err==ZIP_OK)
{
uLong uAvailOutBefore;
if (zi->ci.stream.avail_out == 0)
{
if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
err = ZIP_ERRNO;
zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
zi->ci.stream.next_out = zi->ci.buffered_data;
}
uAvailOutBefore = zi->ci.stream.avail_out;
err=deflate(&zi->ci.stream, Z_FINISH);
zi->ci.pos_in_buffered_data += uAvailOutBefore - zi->ci.stream.avail_out;
}
}
if (err==Z_STREAM_END)
err=ZIP_OK; /* this is normal */
if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
{
if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO)
err = ZIP_ERRNO;
}
if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
{
int tmp_err = deflateEnd(&zi->ci.stream);
if (err == ZIP_OK)
err = tmp_err;
zi->ci.stream_initialised = 0;
}
#ifdef HAVE_BZIP2
else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
{
int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream);
if (err==ZIP_OK)
err = tmperr;
zi->ci.stream_initialised = 0;
}
#endif
if (!zi->ci.raw)
{
crc32 = (uLong)zi->ci.crc32;
uncompressed_size = zi->ci.totalUncompressedData;
}
compressed_size = zi->ci.totalCompressedData;
# ifndef NOCRYPT
compressed_size += zi->ci.crypt_header_size;
# endif
/* update Current Item crc and sizes, */
if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
{
/*version Made by*/
zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2);
/*version needed*/
- zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2);
-
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)((zi->ci.flag & ZIP_ENCODING_UTF8) ? 63 : 45),2);
}
zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
if(compressed_size >= 0xffffffff)
zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/
else
zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/
/* set internal file attributes field */
if (zi->ci.stream.data_type == Z_ASCII)
zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
if(uncompressed_size >= 0xffffffff)
zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/
else
zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/
/* Add ZIP64 extra info field for uncompressed size */
if(uncompressed_size >= 0xffffffff)
datasize += 8;
/* Add ZIP64 extra info field for compressed size */
if(compressed_size >= 0xffffffff)
datasize += 8;
/* Add ZIP64 extra info field for relative offset to local file header of current file */
if(zi->ci.pos_local_header >= 0xffffffff)
datasize += 8;
if(datasize > 0)
{
char* p = NULL;
if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
{
/* we can not write more data to the buffer that we have room for. */
return ZIP_BADZIPFILE;
}
p = zi->ci.central_header + zi->ci.size_centralheader;
/* Add Extra Information Header for 'ZIP64 information' */
zip64local_putValue_inmemory(p, 0x0001, 2); /* HeaderID */
p += 2;
zip64local_putValue_inmemory(p, datasize, 2); /* DataSize */
p += 2;
if(uncompressed_size >= 0xffffffff)
{
zip64local_putValue_inmemory(p, uncompressed_size, 8);
p += 8;
}
if(compressed_size >= 0xffffffff)
{
zip64local_putValue_inmemory(p, compressed_size, 8);
p += 8;
}
if(zi->ci.pos_local_header >= 0xffffffff)
{
zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);
p += 8;
}
/* Update how much extra free space we got in the memory buffer */
/* and increase the centralheader size so the new ZIP64 fields are included */
/* ( 4 below is the size of HeaderID and DataSize field ) */
zi->ci.size_centralExtraFree -= datasize + 4;
zi->ci.size_centralheader += datasize + 4;
/* Update the extra info size field */
zi->ci.size_centralExtra += datasize + 4;
zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2);
}
if (err==ZIP_OK)
err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader);
- free(zi->ci.central_header);
+ TRYFREE(zi->ci.central_header);
if (err==ZIP_OK)
{
if ((zi->flags & ZIP_SEQUENTIAL) == 0) {
/* Update the LocalFileHeader with the new values. */
ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
err = ZIP_ERRNO;
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff)
{
if(zi->ci.pos_zip64extrainfo > 0)
{
/* Update the size in the ZIP64 extended field. */
if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
err = ZIP_ERRNO;
if (err==ZIP_OK) /* compressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);
if (err==ZIP_OK) /* uncompressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);
}
}
else
{
if (err==ZIP_OK) /* compressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
if (err==ZIP_OK) /* uncompressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
}
if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
err = ZIP_ERRNO;
}
if ((zi->ci.flag & 8) != 0) {
/* Write local Descriptor after file data */
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4);
if (err==ZIP_OK)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
if (zi->ci.zip64) {
if (err==ZIP_OK) /* compressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,8);
if (err==ZIP_OK) /* uncompressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,8);
} else {
if (err==ZIP_OK) /* compressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
if (err==ZIP_OK) /* uncompressed size, unknown */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
}
}
}
zi->number_entry ++;
zi->in_opened_file_inzip = 0;
return err;
}
extern int ZEXPORT zipCloseFileInZip (zipFile file)
{
return zipCloseFileInZipRaw (file,0,0);
}
int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip)
{
int err = ZIP_OK;
ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4);
/*num disks*/
if (err==ZIP_OK) /* number of the disk with the start of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
/*relative offset*/
if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
/*total disks*/ /* Do not support spawning of disk so always say 1 here*/
if (err==ZIP_OK) /* number of the disk with the start of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4);
return err;
}
int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
{
int err = ZIP_OK;
uLong Zip64DataSize = 44;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);
if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); /* why ZPOS64_T of this ? */
if (err==ZIP_OK) /* version made by */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
if (err==ZIP_OK) /* version needed */
- err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)((zi->ci.flag & ZIP_ENCODING_UTF8) ? 63 : 45),2);
if (err==ZIP_OK) /* number of this disk */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
if (err==ZIP_OK) /* number of the disk with the start of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
if (err==ZIP_OK) /* total number of entries in the central dir */
err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
if (err==ZIP_OK) /* size of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8);
if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
{
ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);
}
return err;
}
int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
{
int err = ZIP_OK;
/*signature*/
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
if (err==ZIP_OK) /* number of this disk */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
if (err==ZIP_OK) /* number of the disk with the start of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
{
{
if(zi->number_entry >= 0xFFFF)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); /* use value in ZIP64 record */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
}
}
if (err==ZIP_OK) /* total number of entries in the central dir */
{
if(zi->number_entry >= 0xFFFF)
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); /* use value in ZIP64 record */
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
}
if (err==ZIP_OK) /* size of the central directory */
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
{
ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
if(pos >= 0xffffffff)
{
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4);
}
else
err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
}
return err;
}
int Write_GlobalComment(zip64_internal* zi, const char* global_comment)
{
int err = ZIP_OK;
uInt size_global_comment = 0;
if(global_comment != NULL)
size_global_comment = (uInt)strlen(global_comment);
err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
if (err == ZIP_OK && size_global_comment > 0)
{
if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
err = ZIP_ERRNO;
}
return err;
}
extern int ZEXPORT zipClose (zipFile file, const char* global_comment)
{
zip64_internal* zi;
int err = 0;
uLong size_centraldir = 0;
ZPOS64_T centraldir_pos_inzip;
ZPOS64_T pos;
if (file == NULL)
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
if (zi->in_opened_file_inzip == 1)
{
err = zipCloseFileInZip (file);
}
#ifndef NO_ADDFILEINEXISTINGZIP
if (global_comment==NULL)
global_comment = zi->globalcomment;
#endif
centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
if (err==ZIP_OK)
{
linkedlist_datablock_internal* ldi = zi->central_dir.first_block;
while (ldi!=NULL)
{
if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
{
if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block)
err = ZIP_ERRNO;
}
size_centraldir += ldi->filled_in_this_block;
ldi = ldi->next_datablock;
}
}
free_linkedlist(&(zi->central_dir));
pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
if(pos >= 0xffffffff || zi->number_entry > 0xFFFF)
{
ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);
}
if (err==ZIP_OK)
err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
if(err == ZIP_OK)
err = Write_GlobalComment(zi, global_comment);
if ((zi->flags & ZIP_AUTO_CLOSE) != 0) {
if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) {
if (err == ZIP_OK)
err = ZIP_ERRNO;
}
} else {
if (ZFAKECLOSE64(zi->z_filefunc,zi->filestream) != 0) {
if (err == ZIP_OK)
err = ZIP_ERRNO;
}
}
#ifndef NO_ADDFILEINEXISTINGZIP
TRYFREE(zi->globalcomment);
#endif
TRYFREE(zi);
return err;
}
extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader)
{
char* p = pData;
int size = 0;
char* pNewHeader;
char* pTmp;
short header;
short dataSize;
int retVal = ZIP_OK;
if(pData == NULL || *dataLen < 4)
return ZIP_PARAMERROR;
pNewHeader = (char*)ALLOC(*dataLen);
if(!pNewHeader) {
return Z_MEM_ERROR;
}
pTmp = pNewHeader;
while(p < (pData + *dataLen))
{
header = *(short*)p;
dataSize = *(((short*)p)+1);
if( header == sHeader ) /* Header found. */
{
p += dataSize + 4; /* skip it. do not copy to temp buffer */
}
else
{
/* Extra Info block should not be removed, So copy it to the temp buffer. */
memcpy(pTmp, p, dataSize + 4);
p += dataSize + 4;
size += dataSize + 4;
}
}
if(size < *dataLen)
{
/* clean old extra info block. */
memset(pData,0, *dataLen);
/* copy the new extra info block over the old */
if(size > 0)
memcpy(pData, pNewHeader, size);
/* set the new extra info size */
*dataLen = size;
retVal = ZIP_OK;
}
else
retVal = ZIP_ERRNO;
TRYFREE(pNewHeader);
return retVal;
}
int ZEXPORT zipSetFlags(zipFile file, unsigned flags)
{
zip64_internal* zi;
if (file == NULL)
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
zi->flags |= flags;
// If the output is non-seekable, the data descriptor is needed.
if ((zi->flags & ZIP_SEQUENTIAL) != 0) {
zi->flags |= ZIP_WRITE_DATA_DESCRIPTOR;
}
return ZIP_OK;
}
int ZEXPORT zipClearFlags(zipFile file, unsigned flags)
{
zip64_internal* zi;
if (file == NULL)
return ZIP_PARAMERROR;
zi = (zip64_internal*)file;
zi->flags &= ~flags;
// If the data descriptor is not written, we can't use a non-seekable output.
if ((zi->flags & ZIP_WRITE_DATA_DESCRIPTOR) == 0) {
zi->flags &= ~ZIP_SEQUENTIAL;
}
return ZIP_OK;
}
diff --git a/quazip/zip.h b/quazip/zip.h
--- a/quazip/zip.h
+++ b/quazip/zip.h
@@ -1,382 +1,383 @@
/* zip.h -- IO on .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
---------------------------------------------------------------------------
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
---------------------------------------------------------------------------
Changes
See header of zip.h
---------------------------------------------------------------------------
As per the requirement above, this file is plainly marked as modified
by Sergey A. Tachenov. Most modifications include the I/O API redesign
to support QIODevice interface. Some improvements and small fixes were also made.
*/
#ifndef _zip12_H
#define _zip12_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _ZLIB_H
-#include "zlib.h"
+#include <zlib.h>
#endif
#ifndef _ZLIBIOAPI_H
#include "ioapi.h"
#endif
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagzipFile__ { int unused; } zipFile__;
typedef zipFile__ *zipFile;
#else
typedef voidp zipFile;
#endif
#define ZIP_OK (0)
#define ZIP_EOF (0)
#define ZIP_ERRNO (Z_ERRNO)
#define ZIP_PARAMERROR (-102)
#define ZIP_BADZIPFILE (-103)
#define ZIP_INTERNALERROR (-104)
#define ZIP_WRITE_DATA_DESCRIPTOR 0x8u
#define ZIP_AUTO_CLOSE 0x1u
#define ZIP_SEQUENTIAL 0x2u
+#define ZIP_ENCODING_UTF8 0x0800u
#define ZIP_DEFAULT_FLAGS (ZIP_AUTO_CLOSE | ZIP_WRITE_DATA_DESCRIPTOR)
#ifndef DEF_MEM_LEVEL
# if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
# else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
# endif
#endif
/* default memLevel */
/* tm_zip contain date/time info */
typedef struct tm_zip_s
{
uInt tm_sec; /* seconds after the minute - [0,59] */
uInt tm_min; /* minutes after the hour - [0,59] */
uInt tm_hour; /* hours since midnight - [0,23] */
uInt tm_mday; /* day of the month - [1,31] */
uInt tm_mon; /* months since January - [0,11] */
uInt tm_year; /* years - [1980..2044] */
} tm_zip;
typedef struct
{
tm_zip tmz_date; /* date in understandable format */
uLong dosDate; /* if dos_date == 0, tmu_date is used */
/* uLong flag; */ /* general purpose bit flag 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
} zip_fileinfo;
typedef const char* zipcharpc;
#define APPEND_STATUS_CREATE (0)
#define APPEND_STATUS_CREATEAFTER (1)
#define APPEND_STATUS_ADDINZIP (2)
extern zipFile ZEXPORT zipOpen OF((voidpf file, int append));
extern zipFile ZEXPORT zipOpen64 OF((voidpf file, int append));
/*
Create a zipfile.
the file argument depends on the API used, for QuaZIP it's a QIODevice
pointer.
if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
will be created at the end of the file.
(useful if the file contain a self extractor code)
if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
add files in existing zip (be sure you don't add file that doesn't exist)
If the zipfile cannot be opened, the return value is NULL.
Else, the return value is a zipFile Handle, usable with other function
of this zip package.
*/
/* Note : there is no delete function into a zipfile.
If you want delete file into a zipfile, you must open a zipfile, and create another
Of couse, you can use RAW reading and writing to copy the file you did not want delte
*/
extern zipFile ZEXPORT zipOpen2 OF((voidpf file,
int append,
zipcharpc* globalcomment,
zlib_filefunc_def* pzlib_filefunc_def));
extern zipFile ZEXPORT zipOpen2_64 OF((voidpf file,
int append,
zipcharpc* globalcomment,
zlib_filefunc64_def* pzlib_filefunc_def));
/*
* Exported by Sergey A. Tachenov to suit the needs of QuaZIP.
* Note that this function MAY change signature in order to
* provide new QuaZIP features. You have been warned!
* */
extern zipFile ZEXPORT zipOpen3 (voidpf file,
int append,
zipcharpc* globalcomment,
zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
unsigned flags);
extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level));
extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int zip64));
/*
Open a file in the ZIP for writing.
filename : the filename in zip (if NULL, '-' without quote will be used
*zipfi contain supplemental information
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
contains the extrafield data the the local header
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
contains the extrafield data the the local header
if comment != NULL, comment contain the comment string
method contain the compression method (0 for store, Z_DEFLATED for deflate)
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
this MUST be '1' if the uncompressed size is >= 0xffffffff.
*/
extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw));
extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int zip64));
/*
Same than zipOpenNewFileInZip, except if raw=1, we write raw file
*/
extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting));
extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
int zip64
));
/*
Same than zipOpenNewFileInZip2, except
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
password : crypting password (NULL for no crypting)
crcForCrypting : crc of file to compress (needed for crypting)
*/
extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
uLong versionMadeBy,
uLong flagBase
));
extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
uLong versionMadeBy,
uLong flagBase,
int zip64
));
/*
Same than zipOpenNewFileInZip4, except
versionMadeBy : value for Version made by field
flag : value for flag field (compression level info will be added)
*/
extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
const void* buf,
unsigned len));
/*
Write data in the zipfile
*/
extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
/*
Close the current file in the zipfile
*/
extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
uLong uncompressed_size,
uLong crc32));
extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file,
ZPOS64_T uncompressed_size,
uLong crc32));
/*
Close the current file in the zipfile, for file opened with
parameter raw=1 in zipOpenNewFileInZip2
uncompressed_size and crc32 are value for the uncompressed size
*/
extern int ZEXPORT zipClose OF((zipFile file,
const char* global_comment));
/*
Close the zipfile
*/
extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));
/*
zipRemoveExtraInfoBlock - Added by Mathias Svensson
Remove extra information block from a extra information data for the local file header or central directory header
It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
0x0001 is the signature header for the ZIP64 extra information blocks
usage.
Remove ZIP64 Extra information from a central director extra field data
zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
Remove ZIP64 Extra information from a Local File Header extra field data
zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
*/
/*
Added by Sergey A. Tachenov to tweak zipping behaviour.
*/
extern int ZEXPORT zipSetFlags(zipFile file, unsigned flags);
extern int ZEXPORT zipClearFlags(zipFile file, unsigned flags);
#ifdef __cplusplus
}
#endif
#endif /* _zip64_H */
diff --git a/qztest/JlCompress.cpp b/qztest/JlCompress.cpp
--- a/qztest/JlCompress.cpp
+++ b/qztest/JlCompress.cpp
@@ -1,454 +1,466 @@
/*
Copyright (C) 2010 Roberto Pompermaier
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "JlCompress.h"
-#include <QDebug>
static bool copyData(QIODevice &inFile, QIODevice &outFile)
{
while (!inFile.atEnd()) {
char buf[4096];
qint64 readLen = inFile.read(buf, 4096);
if (readLen <= 0)
return false;
if (outFile.write(buf, readLen) != readLen)
return false;
}
return true;
}
bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) {
// zip: oggetto dove aggiungere il file
// fileName: nome del file reale
// fileDest: nome del file all'interno del file compresso
// Controllo l'apertura dello zip
if (!zip) return false;
if (zip->getMode()!=QuaZip::mdCreate &&
zip->getMode()!=QuaZip::mdAppend &&
zip->getMode()!=QuaZip::mdAdd) return false;
// Apro il file originale
QFile inFile;
inFile.setFileName(fileName);
if(!inFile.open(QIODevice::ReadOnly)) return false;
// Apro il file risulato
QuaZipFile outFile(zip);
if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false;
// Copio i dati
if (!copyData(inFile, outFile) || outFile.getZipError()!=UNZ_OK) {
return false;
}
// Chiudo i file
outFile.close();
if (outFile.getZipError()!=UNZ_OK) return false;
inFile.close();
return true;
}
bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive, QDir::Filters filters) {
// zip: oggetto dove aggiungere il file
// dir: cartella reale corrente
// origDir: cartella reale originale
// (path(dir)-path(origDir)) = path interno all'oggetto zip
// Controllo l'apertura dello zip
if (!zip) return false;
if (zip->getMode()!=QuaZip::mdCreate &&
zip->getMode()!=QuaZip::mdAppend &&
zip->getMode()!=QuaZip::mdAdd) return false;
// Controllo la cartella
QDir directory(dir);
if (!directory.exists()) return false;
QDir origDirectory(origDir);
if (dir != origDir) {
QuaZipFile dirZipFile(zip);
if (!dirZipFile.open(QIODevice::WriteOnly,
- QuaZipNewInfo(origDirectory.relativeFilePath(dir) + "/", dir), 0, 0, 0)) {
+ QuaZipNewInfo(origDirectory.relativeFilePath(dir) + QLatin1String("/"), dir), 0, 0, 0)) {
return false;
}
dirZipFile.close();
}
// Se comprimo anche le sotto cartelle
if (recursive) {
// Per ogni sotto cartella
QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot|filters);
for (int index = 0; index < files.size(); ++index ) {
const QFileInfo & file( files.at( index ) );
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 4)
if (!file.isDir())
continue;
#endif
// Comprimo la sotto cartella
if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive,filters)) return false;
}
}
// Per ogni file nella cartella
QFileInfoList files = directory.entryInfoList(QDir::Files|filters);
for (int index = 0; index < files.size(); ++index ) {
const QFileInfo & file( files.at( index ) );
// Se non e un file o e il file compresso che sto creando
if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue;
// Creo il nome relativo da usare all'interno del file compresso
QString filename = origDirectory.relativeFilePath(file.absoluteFilePath());
// Comprimo il file
if (!compressFile(zip,file.absoluteFilePath(),filename)) return false;
}
return true;
}
bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) {
// zip: oggetto dove aggiungere il file
// filename: nome del file reale
// fileincompress: nome del file all'interno del file compresso
// Controllo l'apertura dello zip
if (!zip) return false;
if (zip->getMode()!=QuaZip::mdUnzip) return false;
// Apro il file compresso
if (!fileName.isEmpty())
zip->setCurrentFile(fileName);
QuaZipFile inFile(zip);
if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false;
// Controllo esistenza cartella file risultato
QDir curDir;
- if (fileDest.endsWith('/')) {
+ if (fileDest.endsWith(QLatin1String("/"))) {
if (!curDir.mkpath(fileDest)) {
return false;
}
} else {
if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) {
return false;
}
}
QuaZipFileInfo64 info;
if (!zip->getCurrentFileInfo(&info))
return false;
QFile::Permissions srcPerm = info.getPermissions();
- if (fileDest.endsWith('/') && QFileInfo(fileDest).isDir()) {
+ if (fileDest.endsWith(QLatin1String("/")) && QFileInfo(fileDest).isDir()) {
if (srcPerm != 0) {
QFile(fileDest).setPermissions(srcPerm);
}
return true;
}
// Apro il file risultato
QFile outFile;
outFile.setFileName(fileDest);
if(!outFile.open(QIODevice::WriteOnly)) return false;
// Copio i dati
if (!copyData(inFile, outFile) || inFile.getZipError()!=UNZ_OK) {
outFile.close();
removeFile(QStringList(fileDest));
return false;
}
outFile.close();
// Chiudo i file
inFile.close();
if (inFile.getZipError()!=UNZ_OK) {
removeFile(QStringList(fileDest));
return false;
}
if (srcPerm != 0) {
outFile.setPermissions(srcPerm);
}
return true;
}
bool JlCompress::removeFile(QStringList listFile) {
bool ret = true;
// Per ogni file
for (int i=0; i<listFile.count(); i++) {
// Lo elimino
ret = ret && QFile::remove(listFile.at(i));
}
return ret;
}
bool JlCompress::compressFile(QString fileCompressed, QString file) {
// Creo lo zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}
// Aggiungo il file
if (!compressFile(&zip,file,QFileInfo(file).fileName())) {
QFile::remove(fileCompressed);
return false;
}
// Chiudo il file zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}
return true;
}
bool JlCompress::compressFiles(QString fileCompressed, QStringList files) {
// Creo lo zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}
// Comprimo i file
QFileInfo info;
for (int index = 0; index < files.size(); ++index ) {
const QString & file( files.at( index ) );
info.setFile(file);
if (!info.exists() || !compressFile(&zip,file,info.fileName())) {
QFile::remove(fileCompressed);
return false;
}
}
// Chiudo il file zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}
return true;
}
bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) {
- return compressDir(fileCompressed, dir, recursive, 0);
+ return compressDir(fileCompressed, dir, recursive, {});
}
bool JlCompress::compressDir(QString fileCompressed, QString dir,
bool recursive, QDir::Filters filters)
{
// Creo lo zip
QuaZip zip(fileCompressed);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if(!zip.open(QuaZip::mdCreate)) {
QFile::remove(fileCompressed);
return false;
}
// Aggiungo i file e le sotto cartelle
if (!compressSubDir(&zip,dir,dir,recursive, filters)) {
QFile::remove(fileCompressed);
return false;
}
// Chiudo il file zip
zip.close();
if(zip.getZipError()!=0) {
QFile::remove(fileCompressed);
return false;
}
return true;
}
QString JlCompress::extractFile(QString fileCompressed, QString fileName, QString fileDest) {
// Apro lo zip
QuaZip zip(fileCompressed);
return extractFile(zip, fileName, fileDest);
}
QString JlCompress::extractFile(QuaZip &zip, QString fileName, QString fileDest)
{
if(!zip.open(QuaZip::mdUnzip)) {
return QString();
}
// Estraggo il file
if (fileDest.isEmpty())
fileDest = fileName;
if (!extractFile(&zip,fileName,fileDest)) {
return QString();
}
// Chiudo il file zip
zip.close();
if(zip.getZipError()!=0) {
removeFile(QStringList(fileDest));
return QString();
}
return QFileInfo(fileDest).absoluteFilePath();
}
QStringList JlCompress::extractFiles(QString fileCompressed, QStringList files, QString dir) {
// Creo lo zip
QuaZip zip(fileCompressed);
return extractFiles(zip, files, dir);
}
QStringList JlCompress::extractFiles(QuaZip &zip, const QStringList &files, const QString &dir)
{
if(!zip.open(QuaZip::mdUnzip)) {
return QStringList();
}
// Estraggo i file
QStringList extracted;
for (int i=0; i<files.count(); i++) {
QString absPath = QDir(dir).absoluteFilePath(files.at(i));
if (!extractFile(&zip, files.at(i), absPath)) {
removeFile(extracted);
return QStringList();
}
extracted.append(absPath);
}
// Chiudo il file zip
zip.close();
if(zip.getZipError()!=0) {
removeFile(extracted);
return QStringList();
}
return extracted;
}
-QStringList JlCompress::extractDir(QString fileCompressed, QString dir) {
+QStringList JlCompress::extractDir(QString fileCompressed, QTextCodec* fileNameCodec, QString dir) {
// Apro lo zip
QuaZip zip(fileCompressed);
+ if (fileNameCodec)
+ zip.setFileNameCodec(fileNameCodec);
return extractDir(zip, dir);
}
+QStringList JlCompress::extractDir(QString fileCompressed, QString dir) {
+ return extractDir(fileCompressed, NULL, dir);
+}
+
QStringList JlCompress::extractDir(QuaZip &zip, const QString &dir)
{
if(!zip.open(QuaZip::mdUnzip)) {
return QStringList();
}
QString cleanDir = QDir::cleanPath(dir);
QDir directory(cleanDir);
QString absCleanDir = directory.absolutePath();
QStringList extracted;
if (!zip.goToFirstFile()) {
return QStringList();
}
do {
QString name = zip.getCurrentFileName();
QString absFilePath = directory.absoluteFilePath(name);
QString absCleanPath = QDir::cleanPath(absFilePath);
- if (!absCleanPath.startsWith(absCleanDir + "/"))
+ if (!absCleanPath.startsWith(absCleanDir + QLatin1String("/")))
continue;
- if (!extractFile(&zip, "", absFilePath)) {
+ if (!extractFile(&zip, QLatin1String(""), absFilePath)) {
removeFile(extracted);
return QStringList();
}
extracted.append(absFilePath);
} while (zip.goToNextFile());
// Chiudo il file zip
zip.close();
if(zip.getZipError()!=0) {
removeFile(extracted);
return QStringList();
}
return extracted;
}
QStringList JlCompress::getFileList(QString fileCompressed) {
// Apro lo zip
QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
return getFileList(zip);
}
QStringList JlCompress::getFileList(QuaZip *zip)
{
if(!zip->open(QuaZip::mdUnzip)) {
delete zip;
return QStringList();
}
// Estraggo i nomi dei file
QStringList lst;
QuaZipFileInfo64 info;
for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) {
if(!zip->getCurrentFileInfo(&info)) {
delete zip;
return QStringList();
}
lst << info.name;
//info.name.toLocal8Bit().constData()
}
// Chiudo il file zip
zip->close();
if(zip->getZipError()!=0) {
delete zip;
return QStringList();
}
delete zip;
return lst;
}
+QStringList JlCompress::extractDir(QIODevice* ioDevice, QTextCodec* fileNameCodec, QString dir)
+{
+ QuaZip zip(ioDevice);
+ if (fileNameCodec)
+ zip.setFileNameCodec(fileNameCodec);
+ return extractDir(zip, dir);
+}
+
QStringList JlCompress::extractDir(QIODevice *ioDevice, QString dir)
{
- QuaZip zip(ioDevice);
- return extractDir(zip, dir);
+ return extractDir(ioDevice, NULL, dir);
}
QStringList JlCompress::getFileList(QIODevice *ioDevice)
{
QuaZip *zip = new QuaZip(ioDevice);
return getFileList(zip);
}
QString JlCompress::extractFile(QIODevice *ioDevice, QString fileName, QString fileDest)
{
QuaZip zip(ioDevice);
return extractFile(zip, fileName, fileDest);
}
QStringList JlCompress::extractFiles(QIODevice *ioDevice, QStringList files, QString dir)
{
QuaZip zip(ioDevice);
return extractFiles(zip, files, dir);
}
diff --git a/qztest/JlCompress.h b/qztest/JlCompress.h
--- a/qztest/JlCompress.h
+++ b/qztest/JlCompress.h
@@ -1,197 +1,216 @@
#ifndef JLCOMPRESSFOLDER_H_
#define JLCOMPRESSFOLDER_H_
/*
Copyright (C) 2010 Roberto Pompermaier
Copyright (C) 2005-2016 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "quazip/quazip.h"
#include "quazip/quazipfile.h"
#include "quazip/quazipfileinfo.h"
-#include <QString>
-#include <QDir>
-#include <QFileInfo>
-#include <QFile>
+#include <QtCore/QString>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
+#include <QtCore/QTextCodec>
/// Utility class for typical operations.
/**
This class contains a number of useful static functions to perform
simple operations, such as mass ZIP packing or extraction.
*/
class QUAZIP_EXPORT JlCompress {
private:
static QStringList extractDir(QuaZip &zip, const QString &dir);
static QStringList getFileList(QuaZip *zip);
static QString extractFile(QuaZip &zip, QString fileName, QString fileDest);
static QStringList extractFiles(QuaZip &zip, const QStringList &files, const QString &dir);
/// Compress a single file.
/**
\param zip Opened zip to compress the file to.
\param fileName The full path to the source file.
\param fileDest The full name of the file inside the archive.
\return true if success, false otherwise.
*/
static bool compressFile(QuaZip* zip, QString fileName, QString fileDest);
/// Compress a subdirectory.
/**
\param parentZip Opened zip containing the parent directory.
\param dir The full path to the directory to pack.
\param parentDir The full path to the directory corresponding to
the root of the ZIP.
\param recursive Whether to pack sub-directories as well or only
files.
\return true if success, false otherwise.
*/
static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive,
QDir::Filters filters);
/// Extract a single file.
/**
\param zip The opened zip archive to extract from.
\param fileName The full name of the file to extract.
\param fileDest The full path to the destination file.
\return true if success, false otherwise.
*/
static bool extractFile(QuaZip* zip, QString fileName, QString fileDest);
/// Remove some files.
/**
\param listFile The list of files to remove.
\return true if success, false otherwise.
*/
static bool removeFile(QStringList listFile);
public:
/// Compress a single file.
/**
\param fileCompressed The name of the archive.
\param file The file to compress.
\return true if success, false otherwise.
*/
static bool compressFile(QString fileCompressed, QString file);
/// Compress a list of files.
/**
\param fileCompressed The name of the archive.
\param files The file list to compress.
\return true if success, false otherwise.
*/
static bool compressFiles(QString fileCompressed, QStringList files);
/// Compress a whole directory.
/**
Does not compress hidden files. See compressDir(QString, QString, bool, QDir::Filters).
\param fileCompressed The name of the archive.
\param dir The directory to compress.
\param recursive Whether to pack the subdirectories as well, or
just regular files.
\return true if success, false otherwise.
*/
static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true);
/**
* @brief Compress a whole directory.
*
* Unless filters are specified explicitly, packs
* only regular non-hidden files (and subdirs, if @c recursive is true).
* If filters are specified, they are OR-combined with
* <tt>%QDir::AllDirs|%QDir::NoDotAndDotDot</tt> when searching for dirs
* and with <tt>QDir::Files</tt> when searching for files.
*
* @param fileCompressed path to the resulting archive
* @param dir path to the directory being compressed
* @param recursive if true, then the subdirectories are packed as well
* @param filters what to pack, filters are applied both when searching
* for subdirs (if packing recursively) and when looking for files to pack
* @return true on success, false otherwise
*/
static bool compressDir(QString fileCompressed, QString dir,
bool recursive, QDir::Filters filters);
public:
/// Extract a single file.
/**
\param fileCompressed The name of the archive.
\param fileName The file to extract.
\param fileDest The destination file, assumed to be identical to
\a file if left empty.
\return The list of the full paths of the files extracted, empty on failure.
*/
static QString extractFile(QString fileCompressed, QString fileName, QString fileDest = QString());
/// Extract a list of files.
/**
\param fileCompressed The name of the archive.
\param files The file list to extract.
\param dir The directory to put the files to, the current
directory if left empty.
\return The list of the full paths of the files extracted, empty on failure.
*/
static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString());
/// Extract a whole archive.
/**
\param fileCompressed The name of the archive.
\param dir The directory to extract to, the current directory if
left empty.
\return The list of the full paths of the files extracted, empty on failure.
*/
static QStringList extractDir(QString fileCompressed, QString dir = QString());
+ /// Extract a whole archive.
+ /**
+ \param fileCompressed The name of the archive.
+ \param fileNameCodec The codec to use for file names.
+ \param dir The directory to extract to, the current directory if
+ left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QStringList extractDir(QString fileCompressed, QTextCodec* fileNameCodec, QString dir = QString());
/// Get the file list.
/**
\return The list of the files in the archive, or, more precisely, the
list of the entries, including both files and directories if they
are present separately.
*/
static QStringList getFileList(QString fileCompressed);
/// Extract a single file.
/**
\param ioDevice pointer to device with compressed data.
\param fileName The file to extract.
\param fileDest The destination file, assumed to be identical to
\a file if left empty.
\return The list of the full paths of the files extracted, empty on failure.
*/
static QString extractFile(QIODevice *ioDevice, QString fileName, QString fileDest = QString());
/// Extract a list of files.
/**
\param ioDevice pointer to device with compressed data.
\param files The file list to extract.
\param dir The directory to put the files to, the current
directory if left empty.
\return The list of the full paths of the files extracted, empty on failure.
*/
static QStringList extractFiles(QIODevice *ioDevice, QStringList files, QString dir = QString());
/// Extract a whole archive.
/**
\param ioDevice pointer to device with compressed data.
\param dir The directory to extract to, the current directory if
left empty.
\return The list of the full paths of the files extracted, empty on failure.
*/
static QStringList extractDir(QIODevice *ioDevice, QString dir = QString());
+ /// Extract a whole archive.
+ /**
+ \param ioDevice pointer to device with compressed data.
+ \param fileNameCodec The codec to use for file names.
+ \param dir The directory to extract to, the current directory if
+ left empty.
+ \return The list of the full paths of the files extracted, empty on failure.
+ */
+ static QStringList extractDir(QIODevice* ioDevice, QTextCodec* fileNameCodec, QString dir = QString());
/// Get the file list.
/**
\return The list of the files in the archive, or, more precisely, the
list of the entries, including both files and directories if they
are present separately.
*/
static QStringList getFileList(QIODevice *ioDevice);
};
#endif /* JLCOMPRESSFOLDER_H_ */
diff --git a/qztest/qztest.cpp b/qztest/qztest.cpp
--- a/qztest/qztest.cpp
+++ b/qztest/qztest.cpp
@@ -1,217 +1,221 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP test suite.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "qztest.h"
#include "testquazip.h"
#include "testquazipfile.h"
#include "testquaziodevice.h"
#include "testquazipnewinfo.h"
#include "testquazipfileinfo.h"
#include <quazip/quazip.h>
#include <quazip/quazipfile.h>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QTextStream>
#include <QtTest/QtTest>
bool createTestFiles(const QStringList &fileNames, int size, const QString &dir)
{
QDir curDir;
foreach (QString fileName, fileNames) {
QString filePath = QDir(dir).filePath(fileName);
QDir testDir = QFileInfo(filePath).dir();
if (!testDir.exists()) {
if (!curDir.mkpath(testDir.path())) {
qWarning("Couldn't mkpath %s",
testDir.path().toUtf8().constData());
return false;
}
}
if (fileName.endsWith('/')) {
if (!curDir.mkpath(filePath)) {
qWarning("Couldn't mkpath %s",
fileName.toUtf8().constData());
return false;
}
} else {
QFile testFile(filePath);
if (!testFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning("Couldn't create %s",
fileName.toUtf8().constData());
return false;
}
if (size == -1) {
QTextStream testStream(&testFile);
+#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
testStream << "This is a test file named " << fileName << endl;
+#else
+ testStream << "This is a test file named " << fileName << Qt::endl;
+#endif
} else {
for (int i = 0; i < size; ++i) {
testFile.putChar(static_cast<char>('0' + i % 10));
}
}
}
}
return true;
}
bool createTestArchive(QuaZip &zip, const QString &zipName,
const QStringList &fileNames,
QTextCodec *codec,
const QString &dir)
{
if (codec != NULL) {
zip.setFileNameCodec(codec);
}
if (!zip.open(QuaZip::mdCreate)) {
qWarning("Couldn't open %s", zipName.toUtf8().constData());
return false;
}
int i = 0;
QDateTime dt1;
foreach (QString fileName, fileNames) {
QuaZipFile zipFile(&zip);
QString filePath = QDir(dir).filePath(fileName);
QFileInfo fileInfo(filePath);
QuaZipNewInfo newInfo(fileName, filePath);
if (i == 0) // to test code that needs different timestamps
newInfo.dateTime = newInfo.dateTime.addSecs(-60);
else if (i == 1) // will use for the next file too
dt1 = newInfo.dateTime;
else if (i == 2) // to test identical timestamps
newInfo.dateTime = dt1;
if (!zipFile.open(QIODevice::WriteOnly,
newInfo, NULL, 0,
fileInfo.isDir() ? 0 : 8)) {
qWarning("Couldn't open %s in %s", fileName.toUtf8()
.constData(), zipName.toUtf8().constData());
return false;
}
if (!fileInfo.isDir()) {
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning("Couldn't open %s", filePath.toUtf8()
.constData());
return false;
}
while (!file.atEnd()) {
char buf[4096];
qint64 l = file.read(buf, 4096);
if (l <= 0) {
qWarning("Couldn't read %s", filePath.toUtf8()
.constData());
return false;
}
if (zipFile.write(buf, l) != l) {
qWarning("Couldn't write to %s in %s",
filePath.toUtf8().constData(),
zipName.toUtf8().constData());
return false;
}
}
file.close();
}
zipFile.close();
++i;
}
zip.setComment(QString("This is the test archive"));
zip.close();
if (zipName.startsWith("<")) { // something like "<QIODevice pointer>"
return true;
} else {
return QFileInfo(zipName).exists();
}
}
bool createTestArchive(const QString &zipName,
const QStringList &fileNames,
const QString &dir) {
return createTestArchive(zipName, fileNames, NULL, dir);
}
bool createTestArchive(QIODevice *ioDevice,
const QStringList &fileNames,
QTextCodec *codec,
const QString &dir)
{
QuaZip zip(ioDevice);
return createTestArchive(zip, "<QIODevice pointer>", fileNames, codec, dir);
}
bool createTestArchive(const QString &zipName,
const QStringList &fileNames,
QTextCodec *codec,
const QString &dir) {
QuaZip zip(zipName);
return createTestArchive(zip, zipName, fileNames, codec, dir);
}
void removeTestFiles(const QStringList &fileNames, const QString &dir)
{
QDir curDir;
foreach (QString fileName, fileNames) {
curDir.remove(QDir(dir).filePath(fileName));
}
foreach (QString fileName, fileNames) {
QDir fileDir = QFileInfo(QDir(dir).filePath(fileName)).dir();
if (fileDir.exists()) {
// Non-empty dirs won't get removed, and that's good.
curDir.rmpath(fileDir.path());
}
}
}
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
int err = 0;
{
TestQuaZip testQuaZip;
err = qMax(err, QTest::qExec(&testQuaZip, app.arguments()));
}
{
TestQuaZipFile testQuaZipFile;
err = qMax(err, QTest::qExec(&testQuaZipFile, app.arguments()));
}
{
TestQuaZIODevice testQuaZIODevice;
err = qMax(err, QTest::qExec(&testQuaZIODevice, app.arguments()));
}
{
TestQuaZipNewInfo testQuaZipNewInfo;
err = qMax(err, QTest::qExec(&testQuaZipNewInfo, app.arguments()));
}
{
TestQuaZipFileInfo testQuaZipFileInfo;
err = qMax(err, QTest::qExec(&testQuaZipFileInfo, app.arguments()));
}
if (err == 0) {
qDebug("All tests executed successfully");
} else {
qWarning("There were errors in some of the tests above.");
}
return err;
}
diff --git a/qztest/qztest.pro b/qztest/qztest.pro
--- a/qztest/qztest.pro
+++ b/qztest/qztest.pro
@@ -1,45 +1,53 @@
TEMPLATE = app
QT -= gui
QT += network
CONFIG += qtestlib
CONFIG += console
CONFIG -= app_bundle
DEPENDPATH += .
INCLUDEPATH += .
!win32: LIBS += -lz
win32 {
# workaround for qdatetime.h macro bug
DEFINES += NOMINMAX
}
+greaterThan(QT_MAJOR_VERSION, 4) {
+ # disable all the Qt APIs deprecated before Qt 6.0.0
+ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000
+}
+
CONFIG(staticlib): DEFINES += QUAZIP_STATIC
# Input
HEADERS += qztest.h \
JlCompress.h \
testjlcompress.h \
testquaziodevice.h \
testquazipfile.h \
testquazip.h \
testquazipnewinfo.h \
testquazipfileinfo.h
SOURCES += qztest.cpp \
JlCompress.cpp \
testjlcompress.cpp \
testquaziodevice.cpp \
testquazip.cpp \
testquazipfile.cpp \
testquazipnewinfo.cpp \
testquazipfileinfo.cpp
OBJECTS_DIR = .obj
MOC_DIR = .moc
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../quazip/release/ -lquazip
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../quazip/debug/ -lquazipd
else:mac:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../quazip/ -lquazip_debug
else:unix: LIBS += -L$$OUT_PWD/../quazip/ -lquazip
INCLUDEPATH += $$PWD/..
DEPENDPATH += $$PWD/../quazip
+
+RESOURCES += \
+ qztest.qrc
diff --git a/qztest/qztest.qrc b/qztest/qztest.qrc
new file mode 100644
--- /dev/null
+++ b/qztest/qztest.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>test_files/issue43_cant_get_dates.zip</file>
+ </qresource>
+</RCC>
diff --git a/qztest/test_files/issue43_cant_get_dates.zip b/qztest/test_files/issue43_cant_get_dates.zip
new file mode 100644
index 0000000000000000000000000000000000000000..2337e72628c22e2a1c079da839f9db3ba14ac34e
GIT binary patch
literal 597
zc$^FHW@Zs#U}E540D(-M&vh#q85lI!7#JiN1Q}d1iwhD<k~30^oD+d$a7kiGv0h0<
zNoWW!1N-J`=~x&(J1H=Kwt-0N{lD7p_;2uDKTz;sC1=Z$sNK3PIX73??RcQ!5ukh~
zEOmdKTGnE-TT3!eIj_@c;oHPN|9qnPt_h|`Hr>#S2;CpT68E6@&&PJn(;<tizdn;b
zSaM(c@T5~)Hf^u^{(SA5$IENPWJ4y@-Vf!sf8)8-sI@kfZChyW{9haI?Prd>zTs-=
zN-O5H<?|h+UMIf^JNBXHa8Nc^X=+vWbw`%Iyz2D8uVM>|#7>qzn!@i_sd6|;q4?Fq
zCW+=mz7GuBcdgkrRZDT=v{#jCt_yoC1=&x#-_-b~RKfB<h<_r}lEQPYM>Ie6FLHR)
z>|yhX<-oSdc6;-!BhBnPFK2{{Ena4_OHOpxPOtq5+oJRi=kK`Ja;V#IUS;=H-MIAA
zUn|PoPZ;hw?zi<;$liC~EMyNDoK>44dsJJAhsp8CMgKd6UN5>^+L<0J%v(}&{H^BX
zYW4^Af^YQqD{OH&sOi)e|M_W}vHSnue>Rt%{rfX#^EQXdI%PhNcanm7%lywBRjHnq
zR(xNy@%Jjmyu8Qin_lb3F5G@tUu#bH%QumS3h!PJetfwghi~1F?*(<t0p5&E;@r4m
hoRa|tmNbG$-0{x}iT?m^RyL4AMj-SD(jOQ>JODD=`||(*
diff --git a/qztest/testjlcompress.cpp b/qztest/testjlcompress.cpp
--- a/qztest/testjlcompress.cpp
+++ b/qztest/testjlcompress.cpp
@@ -1,392 +1,415 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP test suite.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "testjlcompress.h"
#include "qztest.h"
#include <QDir>
#include <QFileInfo>
+#include <QTextCodec>
#include <QtTest/QtTest>
#include "JlCompress.h"
#ifdef Q_OS_WIN
#include <windows.h>
#endif
void TestJlCompress::compressFile_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QString>("fileName");
QTest::newRow("simple") << "jlsimplefile.zip" << "test0.txt";
}
void TestJlCompress::compressFile()
{
QFETCH(QString, zipName);
QFETCH(QString, fileName);
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(QStringList() << fileName)) {
QFAIL("Can't create test file");
}
QVERIFY(JlCompress::compressFile(zipName, "tmp/" + fileName));
// get the file list and check it
QStringList fileList = JlCompress::getFileList(zipName);
QCOMPARE(fileList.count(), 1);
QVERIFY(fileList[0] == fileName);
// now test the QIODevice* overload of getFileList()
QFile zipFile(zipName);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
fileList = JlCompress::getFileList(zipName);
QCOMPARE(fileList.count(), 1);
QVERIFY(fileList[0] == fileName);
zipFile.close();
removeTestFiles(QStringList() << fileName);
curDir.remove(zipName);
}
void TestJlCompress::compressFiles_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::newRow("simple") << "jlsimplefiles.zip" <<
(QStringList() << "test0.txt" << "test00.txt");
QTest::newRow("different subdirs") << "jlsubdirfiles.zip" <<
(QStringList() << "subdir1/test1.txt" << "subdir2/test2.txt");
}
void TestJlCompress::compressFiles()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(fileNames)) {
QFAIL("Can't create test files");
}
QStringList realNamesList, shortNamesList;
foreach (QString fileName, fileNames) {
QString realName = "tmp/" + fileName;
realNamesList += realName;
shortNamesList += QFileInfo(realName).fileName();
}
QVERIFY(JlCompress::compressFiles(zipName, realNamesList));
// get the file list and check it
QStringList fileList = JlCompress::getFileList(zipName);
QCOMPARE(fileList, shortNamesList);
removeTestFiles(fileNames);
curDir.remove(zipName);
}
void TestJlCompress::compressDir_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QStringList>("expected");
QTest::newRow("simple") << "jldir.zip"
<< (QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
<< (QStringList() << "test0.txt"
<< "testdir1/" << "testdir1/test1.txt"
<< "testdir2/" << "testdir2/test2.txt"
<< "testdir2/subdir/" << "testdir2/subdir/test2sub.txt");
QTest::newRow("empty dirs") << "jldir_empty.zip"
<< (QStringList() << "testdir1/" << "testdir2/testdir3/")
<< (QStringList() << "testdir1/" << "testdir2/"
<< "testdir2/testdir3/");
QTest::newRow("hidden files") << "jldir_hidden.zip"
<< (QStringList() << ".test0.txt" << "test1.txt")
<< (QStringList() << ".test0.txt" << "test1.txt");
}
void TestJlCompress::compressDir()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QStringList, expected);
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(fileNames, -1, "compressDir_tmp")) {
QFAIL("Can't create test files");
}
#ifdef Q_OS_WIN
for (int i = 0; i < fileNames.size(); ++i) {
if (fileNames.at(i).startsWith(".")) {
QString fn = "compressDir_tmp\\" + fileNames.at(i);
SetFileAttributesW(reinterpret_cast<LPCWSTR>(fn.utf16()),
FILE_ATTRIBUTE_HIDDEN);
}
}
#endif
QVERIFY(JlCompress::compressDir(zipName, "compressDir_tmp", true, QDir::Hidden));
// get the file list and check it
QStringList fileList = JlCompress::getFileList(zipName);
- qSort(fileList);
- qSort(expected);
+ fileList.sort();
+ expected.sort();
QCOMPARE(fileList, expected);
removeTestFiles(fileNames, "compressDir_tmp");
curDir.remove(zipName);
}
void TestJlCompress::extractFile_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QString>("fileToExtract");
QTest::addColumn<QString>("destName");
QTest::addColumn<QByteArray>("encoding");
QTest::newRow("simple") << "jlextfile.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
<< "testdir2/test2.txt" << "test2.txt" << QByteArray();
QTest::newRow("russian") << "jlextfilerus.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< QString::fromUtf8("testdir2/тест2.txt")
<< "testdir2/subdir/test2sub.txt")
<< QString::fromUtf8("testdir2/тест2.txt")
<< QString::fromUtf8("тест2.txt") << QByteArray("IBM866");
QTest::newRow("extract dir") << "jlextdir.zip" << (
QStringList() << "testdir1/")
<< "testdir1/" << "testdir1/" << QByteArray();
}
void TestJlCompress::extractFile()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QString, fileToExtract);
QFETCH(QString, destName);
QFETCH(QByteArray, encoding);
QDir curDir;
if (!curDir.mkpath("jlext/jlfile")) {
QFAIL("Couldn't mkpath jlext/jlfile");
}
if (!createTestFiles(fileNames)) {
QFAIL("Couldn't create test files");
}
QFile srcFile("tmp/" + fileToExtract);
QFile::Permissions srcPerm = srcFile.permissions();
// Invert the "write other" flag so permissions
// are NOT default any more. Otherwise it's impossible
// to figure out whether the permissions were set correctly
// or JlCompress failed to set them completely,
// thus leaving them at the default setting.
srcPerm ^= QFile::WriteOther;
QVERIFY(srcFile.setPermissions(srcPerm));
if (!createTestArchive(zipName, fileNames,
QTextCodec::codecForName(encoding))) {
QFAIL("Can't create test archive");
}
QuaZip::setDefaultFileNameCodec(encoding);
QVERIFY(!JlCompress::extractFile(zipName, fileToExtract,
"jlext/jlfile/" + destName).isEmpty());
QFileInfo destInfo("jlext/jlfile/" + destName), srcInfo("tmp/" +
fileToExtract);
QCOMPARE(destInfo.size(), srcInfo.size());
QCOMPARE(destInfo.permissions(), srcInfo.permissions());
curDir.remove("jlext/jlfile/" + destName);
// now test the QIODevice* overload
QFile zipFile(zipName);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
QVERIFY(!JlCompress::extractFile(&zipFile, fileToExtract,
"jlext/jlfile/" + destName).isEmpty());
destInfo = QFileInfo("jlext/jlfile/" + destName);
QCOMPARE(destInfo.size(), srcInfo.size());
QCOMPARE(destInfo.permissions(), srcInfo.permissions());
curDir.remove("jlext/jlfile/" + destName);
if (!fileToExtract.endsWith("/")) {
// If we aren't extracting a directory, we need to check
// that extractFile() fails if there is a directory
// with the same name as the file being extracted.
curDir.mkdir("jlext/jlfile/" + destName);
QVERIFY(JlCompress::extractFile(zipName, fileToExtract,
"jlext/jlfile/" + destName).isEmpty());
}
zipFile.close();
// Here we either delete the target dir or the dir created in the
// test above.
curDir.rmpath("jlext/jlfile/" + destName);
removeTestFiles(fileNames);
curDir.remove(zipName);
}
void TestJlCompress::extractFiles_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QStringList>("filesToExtract");
QTest::newRow("simple") << "jlextfiles.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
<< (QStringList() << "testdir2/test2.txt" << "testdir1/test1.txt");
}
void TestJlCompress::extractFiles()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QStringList, filesToExtract);
QDir curDir;
if (!curDir.mkpath("jlext/jlfiles")) {
QFAIL("Couldn't mkpath jlext/jlfiles");
}
if (!createTestFiles(fileNames)) {
QFAIL("Couldn't create test files");
}
if (!JlCompress::compressDir(zipName, "tmp")) {
QFAIL("Couldn't create test archive");
}
QVERIFY(!JlCompress::extractFiles(zipName, filesToExtract,
"jlext/jlfiles").isEmpty());
foreach (QString fileName, filesToExtract) {
QFileInfo fileInfo("jlext/jlfiles/" + fileName);
QFileInfo extInfo("tmp/" + fileName);
QCOMPARE(fileInfo.size(), extInfo.size());
QCOMPARE(fileInfo.permissions(), extInfo.permissions());
curDir.remove("jlext/jlfiles/" + fileName);
curDir.rmpath(fileInfo.dir().path());
}
// now test the QIODevice* overload
QFile zipFile(zipName);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
QVERIFY(!JlCompress::extractFiles(&zipFile, filesToExtract,
"jlext/jlfiles").isEmpty());
foreach (QString fileName, filesToExtract) {
QFileInfo fileInfo("jlext/jlfiles/" + fileName);
QFileInfo extInfo("tmp/" + fileName);
QCOMPARE(fileInfo.size(), extInfo.size());
QCOMPARE(fileInfo.permissions(), extInfo.permissions());
curDir.remove("jlext/jlfiles/" + fileName);
curDir.rmpath(fileInfo.dir().path());
}
zipFile.close();
curDir.rmpath("jlext/jlfiles");
removeTestFiles(fileNames);
curDir.remove(zipName);
}
void TestJlCompress::extractDir_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QStringList>("expectedExtracted");
+ QTest::addColumn<QByteArray>("fileNameCodecName");
QTest::newRow("simple") << "jlextdir.zip"
<< (QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
<< (QStringList() << "test0.txt" << "testdir1/test1.txt"
- << "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt");
+ << "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
+ << QByteArray();
QTest::newRow("separate dir") << "sepdir.zip"
<< (QStringList() << "laj/" << "laj/lajfile.txt")
- << (QStringList() << "laj/" << "laj/lajfile.txt");
+ << (QStringList() << "laj/" << "laj/lajfile.txt")
+ << QByteArray();
QTest::newRow("Zip Slip") << "zipslip.zip"
<< (QStringList() << "test0.txt" << "../zipslip.txt")
- << (QStringList() << "test0.txt");
+ << (QStringList() << "test0.txt")
+ << QByteArray();
+ QTest::newRow("Cyrillic") << "cyrillic.zip"
+ << (QStringList() << QString::fromUtf8("Ще не вмерла Україна"))
+ << (QStringList() << QString::fromUtf8("Ще не вмерла Україна"))
+ << QByteArray("KOI8-U");
+ QTest::newRow("Japaneses") << "japanese.zip"
+ << (QStringList() << QString::fromUtf8("日本"))
+ << (QStringList() << QString::fromUtf8("日本"))
+ << QByteArray("UTF-8");
}
void TestJlCompress::extractDir()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QStringList, expectedExtracted);
+ QFETCH(QByteArray, fileNameCodecName);
+ QTextCodec *fileNameCodec = NULL;
+ if (!fileNameCodecName.isEmpty())
+ fileNameCodec = QTextCodec::codecForName(fileNameCodecName);
QDir curDir;
if (!curDir.mkpath("jlext/jldir")) {
QFAIL("Couldn't mkpath jlext/jldir");
}
if (!createTestFiles(fileNames)) {
QFAIL("Couldn't create test files");
}
- if (!createTestArchive(zipName, fileNames)) {
+ if (!createTestArchive(zipName, fileNames, fileNameCodec)) {
QFAIL("Couldn't create test archive");
}
QStringList extracted;
- QCOMPARE((extracted = JlCompress::extractDir(zipName, "jlext/jldir"))
- .count(), expectedExtracted.count());
+ if (fileNameCodec == NULL)
+ extracted = JlCompress::extractDir(zipName, "jlext/jldir");
+ else // test both overloads here
+ extracted = JlCompress::extractDir(zipName, fileNameCodec, "jlext/jldir");
+ QCOMPARE(extracted.count(), expectedExtracted.count());
const QString dir = "jlext/jldir/";
foreach (QString fileName, expectedExtracted) {
QString fullName = dir + fileName;
QFileInfo fileInfo(fullName);
QFileInfo extInfo("tmp/" + fileName);
if (!fileInfo.isDir())
QCOMPARE(fileInfo.size(), extInfo.size());
QCOMPARE(fileInfo.permissions(), extInfo.permissions());
curDir.remove(fullName);
curDir.rmpath(fileInfo.dir().path());
QString absolutePath = QDir(dir).absoluteFilePath(fileName);
if (fileInfo.isDir() && !absolutePath.endsWith('/'))
absolutePath += '/';
QVERIFY(extracted.contains(absolutePath));
}
// now test the QIODevice* overload
QFile zipFile(zipName);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
- QCOMPARE((extracted = JlCompress::extractDir(&zipFile, "jlext/jldir"))
- .count(), expectedExtracted.count());
+ if (fileNameCodec == NULL)
+ extracted = JlCompress::extractDir(&zipFile, "jlext/jldir");
+ else // test both overloads here
+ extracted = JlCompress::extractDir(&zipFile, fileNameCodec, "jlext/jldir");
+ QCOMPARE(extracted.count(), expectedExtracted.count());
foreach (QString fileName, expectedExtracted) {
QString fullName = dir + fileName;
QFileInfo fileInfo(fullName);
QFileInfo extInfo("tmp/" + fileName);
if (!fileInfo.isDir())
QCOMPARE(fileInfo.size(), extInfo.size());
QCOMPARE(fileInfo.permissions(), extInfo.permissions());
curDir.remove(fullName);
curDir.rmpath(fileInfo.dir().path());
QString absolutePath = QDir(dir).absoluteFilePath(fileName);
if (fileInfo.isDir() && !absolutePath.endsWith('/'))
absolutePath += '/';
QVERIFY(extracted.contains(absolutePath));
}
zipFile.close();
curDir.rmpath("jlext/jldir");
removeTestFiles(fileNames);
curDir.remove(zipName);
}
void TestJlCompress::zeroPermissions()
{
QuaZip zipCreator("zero.zip");
QVERIFY(zipCreator.open(QuaZip::mdCreate));
QuaZipFile zeroFile(&zipCreator);
QuaZipNewInfo newInfo("zero.txt");
newInfo.externalAttr = 0; // should be zero anyway, but just in case
QVERIFY(zeroFile.open(QIODevice::WriteOnly, newInfo));
zeroFile.close();
zipCreator.close();
QVERIFY(!JlCompress::extractFile("zero.zip", "zero.txt").isEmpty());
QVERIFY(QFile("zero.txt").permissions() != 0);
QDir curDir;
curDir.remove("zero.zip");
curDir.remove("zero.txt");
}
diff --git a/qztest/testquaziodevice.cpp b/qztest/testquaziodevice.cpp
--- a/qztest/testquaziodevice.cpp
+++ b/qztest/testquaziodevice.cpp
@@ -1,112 +1,113 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP test suite.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "testquaziodevice.h"
#include <quazip/quaziodevice.h>
#include <QBuffer>
#include <QByteArray>
#include <QtTest/QtTest>
void TestQuaZIODevice::read()
{
QByteArray buf(256, 0);
z_stream zouts;
zouts.zalloc = (alloc_func) NULL;
zouts.zfree = (free_func) NULL;
zouts.opaque = NULL;
deflateInit(&zouts, Z_DEFAULT_COMPRESSION);
zouts.next_in = reinterpret_cast<Bytef*>(const_cast<char*>("test"));
zouts.avail_in = 4;
zouts.next_out = reinterpret_cast<Bytef*>(buf.data());
zouts.avail_out = buf.size();
deflate(&zouts, Z_FINISH);
deflateEnd(&zouts);
QBuffer testBuffer(&buf);
testBuffer.open(QIODevice::ReadOnly);
QuaZIODevice testDevice(&testBuffer);
QVERIFY(testDevice.open(QIODevice::ReadOnly));
char outBuf[5];
QCOMPARE(testDevice.read(outBuf, 5), static_cast<qint64>(4));
testDevice.close();
QVERIFY(!testDevice.isOpen());
}
void TestQuaZIODevice::readMany()
{
QByteArray buf(256, 0);
z_stream zouts;
zouts.zalloc = (alloc_func) NULL;
zouts.zfree = (free_func) NULL;
zouts.opaque = NULL;
deflateInit(&zouts, Z_DEFAULT_COMPRESSION);
zouts.next_in = reinterpret_cast<Bytef*>(const_cast<char*>("testtest"));
zouts.avail_in = 8;
zouts.next_out = reinterpret_cast<Bytef*>(buf.data());
zouts.avail_out = buf.size();
deflate(&zouts, Z_FINISH);
deflateEnd(&zouts);
QBuffer testBuffer(&buf);
testBuffer.open(QIODevice::ReadOnly);
QuaZIODevice testDevice(&testBuffer);
QVERIFY(testDevice.open(QIODevice::ReadOnly));
char outBuf[4];
QCOMPARE(testDevice.read(outBuf, 4), static_cast<qint64>(4));
QVERIFY(!testDevice.atEnd());
QVERIFY(testDevice.bytesAvailable() > 0);
QCOMPARE(testDevice.read(4).size(), 4);
QCOMPARE(testDevice.bytesAvailable(), static_cast<qint64>(0));
QVERIFY(testDevice.atEnd());
testDevice.close();
QVERIFY(!testDevice.isOpen());
}
void TestQuaZIODevice::write()
{
QByteArray buf(256, 0);
QBuffer testBuffer(&buf);
testBuffer.open(QIODevice::WriteOnly);
QuaZIODevice *testDevice = new QuaZIODevice(&testBuffer);
QCOMPARE(testDevice->getIoDevice(), &testBuffer);
QVERIFY(testDevice->open(QIODevice::WriteOnly));
QCOMPARE(testDevice->write("test", 4), static_cast<qint64>(4));
testDevice->close();
QVERIFY(!testDevice->isOpen());
z_stream zins;
zins.zalloc = (alloc_func) NULL;
zins.zfree = (free_func) NULL;
zins.opaque = NULL;
inflateInit(&zins);
zins.next_in = reinterpret_cast<Bytef*>(buf.data());
zins.avail_in = testBuffer.pos();
char outBuf[5];
zins.next_out = reinterpret_cast<Bytef*>(outBuf);
zins.avail_out = 5;
- inflate(&zins, Z_FINISH);
+ int result = inflate(&zins, Z_FINISH);
+ QCOMPARE(result, Z_STREAM_END);
inflateEnd(&zins);
int size = 5 - zins.avail_out;
QCOMPARE(size, 4);
outBuf[4] = '\0';
QCOMPARE(static_cast<const char*>(outBuf), "test");
delete testDevice; // Test D0 destructor
}
diff --git a/qztest/testquazip.cpp b/qztest/testquazip.cpp
--- a/qztest/testquazip.cpp
+++ b/qztest/testquazip.cpp
@@ -1,441 +1,469 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP test suite.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "testquazip.h"
#include "qztest.h"
#include <QDataStream>
#include <QDir>
#include <QFileInfo>
#include <QHash>
#ifdef QUAZIP_TEST_QSAVEFILE
#include <QSaveFile>
#endif
#include <QTcpServer>
#include <QTcpSocket>
#include <QTextCodec>
#include <QtTest/QtTest>
#include <quazip/quazip.h>
#include "JlCompress.h"
void TestQuaZip::getFileList_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::newRow("simple") << "qzfilelist.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt");
QTest::newRow("russian") << QString::fromUtf8("файл.zip") << (
QStringList() << QString::fromUtf8("test0.txt") << QString::fromUtf8("test1/test1.txt")
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt");
QTest::newRow("japanese") << QString::fromUtf8("テスト.zip") << (
QStringList() << QString::fromUtf8("test.txt"));
QTest::newRow("hebrew") << QString::fromUtf8("פתח תקווה.zip") << (
QStringList() << QString::fromUtf8("test.txt"));
}
void TestQuaZip::getFileList()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
- qSort(fileNames);
+ fileNames.sort();
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(fileNames)) {
QFAIL("Can't create test file");
}
if (!createTestArchive(zipName, fileNames)) {
QFAIL("Can't create test archive");
}
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdUnzip));
QVERIFY(testZip.goToFirstFile());
QString firstFile = testZip.getCurrentFileName();
QStringList fileList = testZip.getFileNameList();
- qSort(fileList);
+ fileList.sort();
QCOMPARE(fileList, fileNames);
QHash<QString, QFileInfo> srcInfo;
foreach (QString fileName, fileNames) {
srcInfo[fileName] = QFileInfo("tmp/" + fileName);
}
QList<QuaZipFileInfo> destList = testZip.getFileInfoList();
QCOMPARE(destList.size(), srcInfo.size());
for (int i = 0; i < destList.size(); i++) {
QCOMPARE(static_cast<qint64>(destList[i].uncompressedSize),
srcInfo[destList[i].name].size());
}
// Now test zip64
QList<QuaZipFileInfo64> destList64 = testZip.getFileInfoList64();
QCOMPARE(destList64.size(), srcInfo.size());
for (int i = 0; i < destList64.size(); i++) {
QCOMPARE(static_cast<qint64>(destList64[i].uncompressedSize),
srcInfo[destList64[i].name].size());
}
// test that we didn't mess up the current file
QCOMPARE(testZip.getCurrentFileName(), firstFile);
testZip.close();
// clean up
removeTestFiles(fileNames);
curDir.remove(zipName);
}
void TestQuaZip::add_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QStringList>("fileNamesToAdd");
QTest::newRow("simple") << "qzadd.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
<< (QStringList() << "testAdd.txt");
}
void TestQuaZip::add()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QStringList, fileNamesToAdd);
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(fileNames)) {
QFAIL("Can't create test file");
}
if (!createTestArchive(zipName, fileNames)) {
QFAIL("Can't create test archive");
}
if (!createTestFiles(fileNamesToAdd)) {
QFAIL("Can't create test files to add");
}
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdUnzip));
// according to the bug #3485459 the global is lost, so we test it
QString globalComment = testZip.getComment();
testZip.close();
QVERIFY(testZip.open(QuaZip::mdAdd));
foreach (QString fileName, fileNamesToAdd) {
QuaZipFile testFile(&testZip);
QVERIFY(testFile.open(QIODevice::WriteOnly,
QuaZipNewInfo(fileName, "tmp/" + fileName)));
QFile inFile("tmp/" + fileName);
QVERIFY(inFile.open(QIODevice::ReadOnly));
testFile.write(inFile.readAll());
inFile.close();
testFile.close();
}
testZip.close();
QVERIFY(testZip.open(QuaZip::mdUnzip));
QStringList allNames = fileNames + fileNamesToAdd;
QCOMPARE(testZip.getEntriesCount(), allNames.size());
QCOMPARE(testZip.getFileNameList(), allNames);
QCOMPARE(testZip.getComment(), globalComment);
testZip.close();
removeTestFiles(fileNames);
removeTestFiles(fileNamesToAdd);
curDir.remove(zipName);
}
void TestQuaZip::setFileNameCodec_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QByteArray>("encoding");
QTest::newRow("russian") << QString::fromUtf8("russian.zip") << (
QStringList() << QString::fromUtf8("тест.txt")) << QByteArray("IBM866");
}
void TestQuaZip::setFileNameCodec()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QByteArray, encoding);
- qSort(fileNames);
+ fileNames.sort();
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(fileNames)) {
QFAIL("Can't create test file");
}
if (!createTestArchive(zipName, fileNames,
QTextCodec::codecForName(encoding))) {
QFAIL("Can't create test archive");
}
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdUnzip));
QStringList fileList = testZip.getFileNameList();
- qSort(fileList);
+ fileList.sort();
QVERIFY(fileList[0] != fileNames[0]);
testZip.close();
testZip.setFileNameCodec(encoding);
QVERIFY(testZip.open(QuaZip::mdUnzip));
fileList = testZip.getFileNameList();
- qSort(fileList);
+ fileList.sort();
QCOMPARE(fileList, fileNames);
testZip.close();
// clean up
removeTestFiles(fileNames);
curDir.remove(zipName);
}
+void TestQuaZip::setOsCode_data()
+{
+ QTest::addColumn<QString>("zipName");
+ QTest::addColumn<uint>("osCode");
+ QTest::newRow("unix") << "unix.zip" << 3u;
+ QTest::newRow("dos") << "dos.zip" << 0u;
+}
+
+void TestQuaZip::setOsCode()
+{
+ QFETCH(QString, zipName);
+ QFETCH(uint, osCode);
+ QuaZip testZip(zipName);
+ testZip.setOsCode(osCode);
+ testZip.open(QuaZip::mdCreate);
+ QCOMPARE(testZip.getOsCode(), osCode);
+ QuaZipFile testZipFile(&testZip);
+ testZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo("test.txt"));
+ testZipFile.close();
+ testZip.close();
+ QuaZip checkZip(zipName);
+ checkZip.open(QuaZip::mdUnzip);
+ checkZip.goToFirstFile();
+ QuaZipFileInfo64 fi;
+ QVERIFY(checkZip.getCurrentFileInfo(&fi));
+ QCOMPARE(static_cast<uint>(fi.versionCreated) >> 8, osCode);
+}
+
void TestQuaZip::setDataDescriptorWritingEnabled()
{
QString zipName = "zip10.zip";
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
QuaZip testZip(zipName);
testZip.setDataDescriptorWritingEnabled(false);
QVERIFY(testZip.open(QuaZip::mdCreate));
QuaZipFile testZipFile(&testZip);
QVERIFY(testZipFile.open(QIODevice::WriteOnly,
QuaZipNewInfo("vegetation_info.xml"), NULL, 0, 0));
QByteArray contents = "<vegetation_info version=\"4096\" />\n";
testZipFile.write(contents);
testZipFile.close();
testZip.close();
QuaZipFile readZipFile(zipName, "vegetation_info.xml");
QVERIFY(readZipFile.open(QIODevice::ReadOnly));
// Test that file is not compressed.
QCOMPARE(readZipFile.csize(), static_cast<qint64>(contents.size()));
readZipFile.close();
QCOMPARE(QFileInfo(zipName).size(), static_cast<qint64>(171));
QFile zipFile(zipName);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
QDataStream zipData(&zipFile);
zipData.setByteOrder(QDataStream::LittleEndian);
quint32 magic = 0;
quint16 versionNeeded = 0;
zipData >> magic;
zipData >> versionNeeded;
QCOMPARE(magic, static_cast<quint32>(0x04034b50));
QCOMPARE(versionNeeded, static_cast<quint16>(10));
zipFile.close();
curDir.remove(zipName);
// now test 2.0
zipName = "zip20.zip";
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
QuaZip testZip20(zipName);
QVERIFY(testZip20.open(QuaZip::mdCreate));
QuaZipFile testZipFile20(&testZip20);
QVERIFY(testZipFile20.open(QIODevice::WriteOnly,
QuaZipNewInfo("vegetation_info.xml"), NULL, 0, 0));
testZipFile20.write("<vegetation_info version=\"4096\" />\n");
testZipFile20.close();
testZip20.close();
QCOMPARE(QFileInfo(zipName).size(),
static_cast<qint64>(171 + 16)); // 16 bytes = data descriptor
QFile zipFile20(zipName);
QVERIFY(zipFile20.open(QIODevice::ReadOnly));
QDataStream zipData20(&zipFile20);
zipData20.setByteOrder(QDataStream::LittleEndian);
magic = 0;
versionNeeded = 0;
zipData20 >> magic;
zipData20 >> versionNeeded;
QCOMPARE(magic, static_cast<quint32>(0x04034b50));
QCOMPARE(versionNeeded, static_cast<quint16>(20));
zipFile20.close();
curDir.remove(zipName);
}
void TestQuaZip::testQIODeviceAPI()
{
QString zipName = "qiodevice_api.zip";
QStringList fileNames;
fileNames << "test.txt";
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(fileNames)) {
QFAIL("Can't create test file");
}
if (!createTestArchive(zipName, fileNames)) {
QFAIL("Can't create test archive");
}
QBuffer buffer;
if (!createTestArchive(&buffer, fileNames, NULL)) {
QFAIL("Can't create test archive");
}
QFile diskFile(zipName);
QVERIFY(diskFile.open(QIODevice::ReadOnly));
QByteArray bufferArray = buffer.buffer();
QByteArray fileArray = diskFile.readAll();
diskFile.close();
QCOMPARE(bufferArray.size(), fileArray.size());
QCOMPARE(bufferArray, fileArray);
curDir.remove(zipName);
}
void TestQuaZip::setZipName()
{
QuaZip zip;
zip.setZipName("testSetZipName.zip");
zip.open(QuaZip::mdCreate);
zip.close();
QVERIFY(QFileInfo(zip.getZipName()).exists());
QDir().remove(zip.getZipName());
}
void TestQuaZip::setIoDevice()
{
QuaZip zip;
QFile file("testSetIoDevice.zip");
zip.setIoDevice(&file);
QCOMPARE(zip.getIoDevice(), &file);
zip.open(QuaZip::mdCreate);
QVERIFY(file.isOpen());
zip.close();
QVERIFY(!file.isOpen());
QVERIFY(file.exists());
QDir().remove(file.fileName());
}
void TestQuaZip::setCommentCodec()
{
QuaZip zip("commentCodec.zip");
QVERIFY(zip.open(QuaZip::mdCreate));
zip.setCommentCodec("WINDOWS-1251");
zip.setComment(QString::fromUtf8("Вопрос"));
QuaZipFile zipFile(&zip);
QVERIFY(zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo("test.txt")));
zipFile.close();
zip.close();
QVERIFY(zip.open(QuaZip::mdUnzip));
zip.setCommentCodec(QTextCodec::codecForName("KOI8-R"));
QCOMPARE(zip.getComment(), QString::fromUtf8("бНОПНЯ"));
zip.close();
QDir().remove(zip.getZipName());
}
void TestQuaZip::setAutoClose()
{
{
QBuffer buf;
QuaZip zip(&buf);
QVERIFY(zip.isAutoClose());
QVERIFY(zip.open(QuaZip::mdCreate));
QVERIFY(buf.isOpen());
zip.close();
QVERIFY(!buf.isOpen());
QVERIFY(zip.open(QuaZip::mdCreate));
}
{
QBuffer buf;
QuaZip zip(&buf);
QVERIFY(zip.isAutoClose());
zip.setAutoClose(false);
QVERIFY(!zip.isAutoClose());
QVERIFY(zip.open(QuaZip::mdCreate));
QVERIFY(buf.isOpen());
zip.close();
QVERIFY(buf.isOpen());
QVERIFY(zip.open(QuaZip::mdCreate));
}
}
#ifdef QUAZIP_TEST_QSAVEFILE
void TestQuaZip::saveFileBug()
{
QDir curDir;
QString zipName = "testSaveFile.zip";
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName)) {
QFAIL("Can't remove testSaveFile.zip");
}
}
QuaZip zip;
QSaveFile saveFile(zipName);
zip.setIoDevice(&saveFile);
QCOMPARE(zip.getIoDevice(), &saveFile);
zip.open(QuaZip::mdCreate);
zip.close();
QVERIFY(QFileInfo(saveFile.fileName()).exists());
curDir.remove(saveFile.fileName());
}
#endif
void TestQuaZip::testSequential()
{
QTcpServer server;
QVERIFY(server.listen(QHostAddress(QHostAddress::LocalHost)));
quint16 port = server.serverPort();
QTcpSocket socket;
socket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
QVERIFY(socket.waitForConnected());
QVERIFY(server.waitForNewConnection(30000));
QTcpSocket *client = server.nextPendingConnection();
QuaZip zip(&socket);
zip.setAutoClose(false);
QVERIFY(zip.open(QuaZip::mdCreate));
QVERIFY(socket.isOpen());
QuaZipFile zipFile(&zip);
QuaZipNewInfo info("test.txt");
QVERIFY(zipFile.open(QIODevice::WriteOnly, info, NULL, 0, 0));
QCOMPARE(zipFile.write("test"), static_cast<qint64>(4));
zipFile.close();
zip.close();
QVERIFY(socket.isOpen());
socket.disconnectFromHost();
QVERIFY(socket.waitForDisconnected());
QVERIFY(client->waitForReadyRead());
QByteArray received = client->readAll();
#ifdef QUAZIP_QZTEST_QUAZIP_DEBUG_SOCKET
QFile debug("testSequential.zip");
debug.open(QIODevice::WriteOnly);
debug.write(received);
debug.close();
#endif
client->close();
QBuffer buffer(&received);
QuaZip receivedZip(&buffer);
QVERIFY(receivedZip.open(QuaZip::mdUnzip));
QVERIFY(receivedZip.goToFirstFile());
QuaZipFileInfo64 receivedInfo;
QVERIFY(receivedZip.getCurrentFileInfo(&receivedInfo));
QCOMPARE(receivedInfo.name, QString::fromLatin1("test.txt"));
QCOMPARE(receivedInfo.uncompressedSize, static_cast<quint64>(4));
QuaZipFile receivedFile(&receivedZip);
QVERIFY(receivedFile.open(QIODevice::ReadOnly));
QByteArray receivedText = receivedFile.readAll();
QCOMPARE(receivedText, QByteArray("test"));
receivedFile.close();
receivedZip.close();
}
diff --git a/qztest/testquazip.h b/qztest/testquazip.h
--- a/qztest/testquazip.h
+++ b/qztest/testquazip.h
@@ -1,55 +1,57 @@
#ifndef QUAZIP_TEST_QUAZIP_H
#define QUAZIP_TEST_QUAZIP_H
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP test suite.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include <QObject>
#if (QT_VERSION >= 0x050100)
#define QUAZIP_TEST_QSAVEFILE
#endif
class TestQuaZip: public QObject {
Q_OBJECT
private slots:
void getFileList_data();
void getFileList();
void add_data();
void add();
void setFileNameCodec_data();
void setFileNameCodec();
+ void setOsCode_data();
+ void setOsCode();
void setDataDescriptorWritingEnabled();
void testQIODeviceAPI();
void setZipName();
void setIoDevice();
void setCommentCodec();
void setAutoClose();
#ifdef QUAZIP_TEST_QSAVEFILE
void saveFileBug();
#endif
void testSequential();
};
#endif // QUAZIP_TEST_QUAZIP_H
diff --git a/qztest/testquazipfile.cpp b/qztest/testquazipfile.cpp
--- a/qztest/testquazipfile.cpp
+++ b/qztest/testquazipfile.cpp
@@ -1,575 +1,590 @@
/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP test suite.
QuaZIP 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.
QuaZIP 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 QuaZIP. If not, see <http://www.gnu.org/licenses/>.
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include "testquazipfile.h"
#include "qztest.h"
#include "JlCompress.h"
#include <quazip/quazipfile.h>
#include <quazip/quazip.h>
#include <QFile>
#include <QString>
#include <QStringList>
#include <QtTest/QtTest>
+#include <QRandomGenerator>
void TestQuaZipFile::zipUnzip_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<QByteArray>("fileNameCodec");
QTest::addColumn<QByteArray>("password");
QTest::addColumn<bool>("zip64");
+ QTest::addColumn<bool>("utf8");
QTest::addColumn<int>("size");
QTest::newRow("simple") << "simple.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
- << QByteArray() << QByteArray() << false << -1;
+ << QByteArray() << QByteArray() << false << false << -1;
QTest::newRow("Cyrillic") << "cyrillic.zip" << (
QStringList()
<< QString::fromUtf8("русское имя файла с пробелами.txt"))
- << QByteArray("IBM866") << QByteArray() << false << -1;
+ << QByteArray("IBM866") << QByteArray() << false << false << -1;
+ QTest::newRow("Unicode") << "unicode.zip" << (
+ QStringList()
+ << QString::fromUtf8("Українське сало.txt")
+ << QString::fromUtf8("Vin français.txt")
+ << QString::fromUtf8("日本の寿司.txt")
+ << QString::fromUtf8("ქართული ხაჭაპური.txt"))
+ << QByteArray("") << QByteArray() << false << true << -1;
QTest::newRow("password") << "password.zip" << (
QStringList() << "test.txt")
- << QByteArray() << QByteArray("PassPass") << false << -1;
+ << QByteArray() << QByteArray("PassPass") << false << false << -1;
QTest::newRow("zip64") << "zip64.zip" << (
QStringList() << "test64.txt")
- << QByteArray() << QByteArray() << true << -1;
+ << QByteArray() << QByteArray() << true << false << -1;
QTest::newRow("large enough to flush") << "flush.zip" << (
QStringList() << "flush.txt")
- << QByteArray() << QByteArray() << true << 65536 * 2;
+ << QByteArray() << QByteArray() << true << false << 65536 * 2;
}
void TestQuaZipFile::zipUnzip()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(QByteArray, fileNameCodec);
QFETCH(QByteArray, password);
QFETCH(bool, zip64);
+ QFETCH(bool, utf8);
QFETCH(int, size);
QFile testFile(zipName);
if (testFile.exists()) {
if (!testFile.remove()) {
QFAIL("Couldn't remove existing archive to create a new one");
}
}
if (!createTestFiles(fileNames, size)) {
QFAIL("Couldn't create test files for zipping");
}
QuaZip testZip(&testFile);
testZip.setZip64Enabled(zip64);
+ testZip.setUtf8Enabled(utf8);
if (!fileNameCodec.isEmpty())
testZip.setFileNameCodec(fileNameCodec);
QVERIFY(testZip.open(QuaZip::mdCreate));
- QString comment = "Test comment";
+ QString comment = utf8 ? "test テスト ჩეკი" : "Test comment";
testZip.setComment(comment);
foreach (QString fileName, fileNames) {
QFile inFile("tmp/" + fileName);
if (!inFile.open(QIODevice::ReadOnly)) {
qDebug("File name: %s", fileName.toUtf8().constData());
QFAIL("Couldn't open input file");
}
QuaZipFile outFile(&testZip);
QVERIFY(outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileName,
inFile.fileName()),
password.isEmpty() ? NULL : password.constData()));
for (qint64 pos = 0, len = inFile.size(); pos < len; ) {
char buf[4096];
qint64 readSize = qMin(static_cast<qint64>(4096), len - pos);
qint64 l;
if ((l = inFile.read(buf, readSize)) != readSize) {
qDebug("Reading %ld bytes from %s at %ld returned %ld",
static_cast<long>(readSize),
fileName.toUtf8().constData(),
static_cast<long>(pos),
static_cast<long>(l));
QFAIL("Read failure");
}
QVERIFY(outFile.write(buf, readSize));
pos += readSize;
}
inFile.close();
outFile.close();
QCOMPARE(outFile.getZipError(), ZIP_OK);
}
testZip.close();
QCOMPARE(testZip.getZipError(), ZIP_OK);
// now test unzip
QuaZip testUnzip(&testFile);
if (!fileNameCodec.isEmpty())
testUnzip.setFileNameCodec(fileNameCodec);
QVERIFY(testUnzip.open(QuaZip::mdUnzip));
QCOMPARE(testUnzip.getComment(), comment);
QVERIFY(testUnzip.goToFirstFile());
foreach (QString fileName, fileNames) {
QuaZipFileInfo64 info;
QVERIFY(testUnzip.getCurrentFileInfo(&info));
QCOMPARE(info.name, fileName);
QCOMPARE(info.isEncrypted(), !password.isEmpty());
QFile original("tmp/" + fileName);
QVERIFY(original.open(QIODevice::ReadOnly));
QuaZipFile archived(&testUnzip);
QVERIFY(archived.open(QIODevice::ReadOnly,
password.isEmpty() ? NULL : password.constData()));
QByteArray originalData = original.readAll();
QByteArray archivedData = archived.readAll();
QCOMPARE(archivedData, originalData);
testUnzip.goToNextFile();
}
if (!password.isEmpty()) {
QVERIFY(testUnzip.goToFirstFile());
QuaZipFileInfo64 info;
QVERIFY(testUnzip.getCurrentFileInfo(&info));
QFile original("tmp/" + info.name);
QVERIFY(original.open(QIODevice::ReadOnly));
QuaZipFile archived(&testUnzip);
QVERIFY(archived.open(QIODevice::ReadOnly, "WrongPassword"));
QByteArray originalData = original.readAll();
QByteArray archivedData = archived.readAll();
QVERIFY(archivedData != originalData);
}
testUnzip.close();
QCOMPARE(testUnzip.getZipError(), UNZ_OK);
// clean up
removeTestFiles(fileNames);
testFile.remove();
}
void TestQuaZipFile::bytesAvailable_data()
{
QTest::addColumn<QString>("zipName");
QTest::addColumn<QStringList>("fileNames");
QTest::addColumn<int>("size");
QTest::newRow("simple") << "test.zip" << (
QStringList() << "test0.txt" << "testdir1/test1.txt"
<< "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt") << -1;
QTest::newRow("large enough to flush")
<< "flush.zip" << (QStringList() << "test.txt") << 65536 * 4;
}
void TestQuaZipFile::bytesAvailable()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(int, size);
QDir curDir;
if (!createTestFiles(fileNames, size)) {
QFAIL("Couldn't create test files");
}
if (!JlCompress::compressDir(zipName, "tmp")) {
QFAIL("Couldn't create test archive");
}
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdUnzip));
foreach (QString fileName, fileNames) {
QFileInfo fileInfo("tmp/" + fileName);
QVERIFY(testZip.setCurrentFile(fileName));
QuaZipFile zipFile(&testZip);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
QCOMPARE(zipFile.bytesAvailable(), fileInfo.size());
QCOMPARE(zipFile.read(1).size(), 1);
QCOMPARE(zipFile.bytesAvailable(), fileInfo.size() - 1);
QCOMPARE(zipFile.read(fileInfo.size() - 1).size(),
static_cast<int>(fileInfo.size() - 1));
QCOMPARE(zipFile.bytesAvailable(), (qint64) 0);
}
removeTestFiles(fileNames);
testZip.close();
curDir.remove(zipName);
}
void TestQuaZipFile::atEnd_data()
{
bytesAvailable_data();
}
void TestQuaZipFile::atEnd()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(int, size);
QDir curDir;
if (!createTestFiles(fileNames, size)) {
QFAIL("Couldn't create test files");
}
if (!JlCompress::compressDir(zipName, "tmp")) {
QFAIL("Couldn't create test archive");
}
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdUnzip));
foreach (QString fileName, fileNames) {
QFileInfo fileInfo("tmp/" + fileName);
QVERIFY(testZip.setCurrentFile(fileName));
QuaZipFile zipFile(&testZip);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
QCOMPARE(zipFile.atEnd(), false);
QCOMPARE(zipFile.read(1).size(), 1);
QCOMPARE(zipFile.atEnd(), false);
QCOMPARE(zipFile.read(fileInfo.size() - 1).size(),
static_cast<int>(fileInfo.size() - 1));
QCOMPARE(zipFile.atEnd(), true);
}
removeTestFiles(fileNames);
testZip.close();
curDir.remove(zipName);
}
void TestQuaZipFile::posRead_data()
{
bytesAvailable_data();
}
void TestQuaZipFile::posRead()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(int, size);
QDir curDir;
if (!createTestFiles(fileNames, size)) {
QFAIL("Couldn't create test files");
}
if (!JlCompress::compressDir(zipName, "tmp")) {
QFAIL("Couldn't create test archive");
}
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdUnzip));
foreach (QString fileName, fileNames) {
QFileInfo fileInfo("tmp/" + fileName);
QVERIFY(testZip.setCurrentFile(fileName));
QuaZipFile zipFile(&testZip);
QVERIFY(zipFile.open(QIODevice::ReadOnly));
QCOMPARE(zipFile.pos(), (qint64) 0);
QCOMPARE(zipFile.read(1).size(), 1);
QCOMPARE(zipFile.pos(), (qint64) 1);
QCOMPARE(zipFile.read(fileInfo.size() - 1).size(),
static_cast<int>(fileInfo.size() - 1));
QCOMPARE(zipFile.pos(), fileInfo.size());
}
removeTestFiles(fileNames);
testZip.close();
curDir.remove(zipName);
}
void TestQuaZipFile::posWrite_data()
{
posRead_data();
}
void TestQuaZipFile::posWrite()
{
QFETCH(QString, zipName);
QFETCH(QStringList, fileNames);
QFETCH(int, size);
if (size == -1)
size = 20;
QDir curDir;
QuaZip testZip(zipName);
QVERIFY(testZip.open(QuaZip::mdCreate));
foreach (QString fileName, fileNames) {
QuaZipFile zipFile(&testZip);
QVERIFY(zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileName)));
QCOMPARE(zipFile.pos(), (qint64) 0);
zipFile.putChar('0');
QCOMPARE(zipFile.pos(), (qint64) 1);
QByteArray buffer(size / 2 - 1, '\0');
for (int i = 0; i < buffer.size(); ++i)
- buffer[i] = static_cast<char>(qrand());
+ buffer[i] = static_cast<char>(QRandomGenerator::global()->generate());
zipFile.write(buffer);
QCOMPARE(zipFile.pos(), qint64(size / 2));
for (int i = 0; i < size - size / 2; ++i) {
- zipFile.putChar(static_cast<char>(qrand()));
+ zipFile.putChar(static_cast<char>(QRandomGenerator::global()->generate()));
}
QCOMPARE(zipFile.pos(), qint64(size));
}
testZip.close();
curDir.remove(zipName);
}
void TestQuaZipFile::getZip()
{
QuaZip testZip;
QuaZipFile f1(&testZip);
QCOMPARE(f1.getZip(), &testZip);
QuaZipFile f2("doesntexist.zip", "someFile");
QCOMPARE(f2.getZip(), static_cast<QuaZip*>(NULL));
f2.setZip(&testZip);
QCOMPARE(f2.getZip(), &testZip);
}
void TestQuaZipFile::setZipName()
{
QString testFileName = "testZipName.txt";
QString testZipName = "testZipName.zip";
QVERIFY(createTestFiles(QStringList() << testFileName));
QVERIFY(createTestArchive(testZipName, QStringList() << testFileName));
QuaZipFile testFile;
testFile.setZipName(testZipName);
QCOMPARE(testFile.getZipName(), testZipName);
testFile.setFileName(testFileName);
QVERIFY(testFile.open(QIODevice::ReadOnly));
testFile.close();
removeTestFiles(QStringList() << testFileName);
QDir curDir;
curDir.remove(testZipName);
}
void TestQuaZipFile::getFileInfo()
{
QuaZipFileInfo info32;
QuaZipFileInfo64 info64;
QString testFileName = "testZipName.txt";
QStringList testFiles;
testFiles << testFileName;
QString testZipName = "testZipName.zip";
QVERIFY(createTestFiles(testFiles));
QVERIFY(createTestArchive(testZipName, testFiles));
QuaZipFile testFile;
testFile.setZipName(testZipName);
testFile.setFileName(testFileName);
QVERIFY(testFile.open(QIODevice::ReadOnly));
QVERIFY(testFile.getFileInfo(&info32));
QVERIFY(testFile.getFileInfo(&info64));
QCOMPARE(info32.name, info64.name);
QCOMPARE(info32.versionCreated, info64.versionCreated);
QCOMPARE(info32.versionNeeded, info64.versionNeeded);
QCOMPARE(info32.flags, info64.flags);
QCOMPARE(info32.method, info64.method);
QCOMPARE(info32.dateTime, info64.dateTime);
QCOMPARE(info32.crc, info64.crc);
QCOMPARE(info32.compressedSize,
static_cast<quint32>(info64.compressedSize));
QCOMPARE(info32.uncompressedSize,
static_cast<quint32>(info64.uncompressedSize));
QCOMPARE(info32.diskNumberStart, info64.diskNumberStart);
QCOMPARE(info32.internalAttr, info64.internalAttr);
QCOMPARE(info32.externalAttr, info64.externalAttr);
QCOMPARE(info32.comment, info64.comment);
QCOMPARE(info32.extra, info64.extra);
testFile.close();
removeTestFiles(testFiles);
QDir curDir;
curDir.remove(testZipName);
}
void TestQuaZipFile::setFileName()
{
QString testFileName = "testZipName.txt";
QString testZipName = "testZipName.zip";
QVERIFY(createTestFiles(QStringList() << testFileName));
QVERIFY(createTestArchive(testZipName, QStringList() << testFileName));
QuaZipFile testFile(testZipName);
testFile.setFileName(testFileName.toUpper());
#ifdef Q_OS_WIN
QVERIFY(testFile.open(QIODevice::ReadOnly));
testFile.close();
#else
QVERIFY(!testFile.open(QIODevice::ReadOnly));
#endif
testFile.setFileName(testFileName.toUpper(), QuaZip::csInsensitive);
QCOMPARE(testFile.getCaseSensitivity(), QuaZip::csInsensitive);
QVERIFY(testFile.open(QIODevice::ReadOnly));
QCOMPARE(testFile.getActualFileName(), testFileName);
testFile.close();
testFile.setFileName(testFileName.toUpper(), QuaZip::csSensitive);
QCOMPARE(testFile.getFileName(), testFileName.toUpper());
QCOMPARE(testFile.getActualFileName(), QString());
QVERIFY(!testFile.open(QIODevice::ReadOnly));
testFile.setFileName(testFileName);
removeTestFiles(QStringList() << testFileName);
QDir curDir;
curDir.remove(testZipName);
}
void TestQuaZipFile::constructorDestructor()
{
// Just test that all constructors and destructors are available.
// (So there are none that are declared but not defined.)
QuaZip testZip;
QuaZipFile *f1 = new QuaZipFile();
delete f1; // test D0 destructor
QObject parent;
QuaZipFile f2(&testZip, &parent);
QuaZipFile f3(&parent);
QuaZipFile f4("zipName.zip");
QuaZipFile f5("zipName.zip", "fileName.txt", QuaZip::csDefault, &parent);
}
void TestQuaZipFile::setFileAttrs()
{
QuaZip testZip("setFileAttrs.zip");
QVERIFY(testZip.open(QuaZip::mdCreate));
QuaZipFile zipFile(&testZip);
QuaZipNewInfo newInfo("testPerm.txt");
newInfo.setPermissions(QFile::ReadOwner);
QVERIFY(zipFile.open(QIODevice::WriteOnly, newInfo));
zipFile.close();
QString fileTestAttr = "testAttr.txt";
QStringList fileNames;
fileNames << fileTestAttr;
QVERIFY(createTestFiles(fileNames));
newInfo.name = fileTestAttr;
newInfo.setFileDateTime("tmp/" + fileTestAttr);
newInfo.setFilePermissions("tmp/" + fileTestAttr);
QVERIFY(zipFile.open(QIODevice::WriteOnly, newInfo));
zipFile.close();
testZip.close();
QuaZipFileInfo64 info;
{
QuaZipFile readFilePerm("setFileAttrs.zip", "testPerm.txt");
QVERIFY(readFilePerm.open(QIODevice::ReadOnly));
QVERIFY(readFilePerm.getFileInfo(&info));
QCOMPARE(info.getPermissions(), QFile::ReadOwner);
readFilePerm.close();
}
{
QuaZipFile readFileAttrs("setFileAttrs.zip", "testAttr.txt");
QVERIFY(readFileAttrs.open(QIODevice::ReadOnly));
QVERIFY(readFileAttrs.getFileInfo(&info));
QFileInfo srcInfo("tmp/" + fileTestAttr);
QFile::Permissions usedPermissions =
QFile::WriteOwner | QFile::ReadOwner | QFile::ExeOwner |
QFile::WriteGroup | QFile::ReadGroup | QFile::ExeGroup |
QFile::WriteOther | QFile::ReadOther | QFile::ExeOther;
QCOMPARE(info.getPermissions() & usedPermissions,
srcInfo.permissions() & usedPermissions);
- // I really hope Qt 6 will use quint64 for time_t!
+#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // Yay! Finally a way to get time as qint64!
+ qint64 newTime = info.dateTime.toSecsSinceEpoch();
+ qint64 oldTime = srcInfo.lastModified().toSecsSinceEpoch();
+#else
quint64 newTime = info.dateTime.toTime_t();
quint64 oldTime = srcInfo.lastModified().toTime_t();
+#endif
// ZIP uses weird format with 2 second precision
QCOMPARE(newTime / 2, oldTime / 2);
readFileAttrs.close();
}
removeTestFiles(fileNames);
QDir().remove(testZip.getZipName());
}
void TestQuaZipFile::largeFile()
{
QDir curDir;
QVERIFY(curDir.mkpath("tmp"));
QFile fakeLargeFile("tmp/large.zip");
QVERIFY(fakeLargeFile.open(QIODevice::WriteOnly));
QDataStream ds(&fakeLargeFile);
ds.setByteOrder(QDataStream::LittleEndian);
QList<qint64> localOffsets;
const int numFiles = 2; // name fixed to 5 bytes, so MAX 10 FILES!!!
for (int i = 0; i < numFiles; ++i) {
localOffsets.append(fakeLargeFile.pos());
QBuffer extra;
extra.open(QIODevice::WriteOnly);
QDataStream es(&extra);
es.setByteOrder(QDataStream::LittleEndian);
// prepare extra
es << static_cast<quint16>(0x0001u); // zip64
es << static_cast<quint16>(16); // extra data size
es << static_cast<quint64>(0); // uncompressed size
es << static_cast<quint64>(0); // compressed size
// now the local header
ds << static_cast<quint32>(0x04034b50u); // local magic
ds << static_cast<quint16>(45); // version needed
ds << static_cast<quint16>(0); // flags
ds << static_cast<quint16>(0); // method
ds << static_cast<quint16>(0); // time 00:00:00
ds << static_cast<quint16>(0x21); // date 1980-01-01
ds << static_cast<quint32>(0); // CRC-32
ds << static_cast<quint32>(0xFFFFFFFFu); // compressed size
ds << static_cast<quint32>(0xFFFFFFFFu); // uncompressed size
ds << static_cast<quint16>(5); // name length
ds << static_cast<quint16>(extra.size()); // extra length
ds.writeRawData("file", 4); // name
ds << static_cast<qint8>('0' + i); // name (contd.)
ds.writeRawData(extra.buffer(), extra.size());
}
// central dir:
qint64 centralStart = fakeLargeFile.pos();
for (int i = 0; i < numFiles; ++i) {
QBuffer extra;
extra.open(QIODevice::WriteOnly);
QDataStream es(&extra);
es.setByteOrder(QDataStream::LittleEndian);
// prepare extra
es << static_cast<quint16>(0x0001u); // zip64
es << static_cast<quint16>(24); // extra data size
es << static_cast<quint64>(0); // uncompressed size
es << static_cast<quint64>(0); // compressed size
es << static_cast<quint64>(localOffsets[i]);
// now the central dir header
ds << static_cast<quint32>(0x02014b50u); // central magic
ds << static_cast<quint16>(45); // version made by
ds << static_cast<quint16>(45); // version needed
ds << static_cast<quint16>(0); // flags
ds << static_cast<quint16>(0); // method
ds << static_cast<quint16>(0); // time 00:00:00
ds << static_cast<quint16>(0x21); // date 1980-01-01
ds << static_cast<quint32>(0); // CRC-32
ds << static_cast<quint32>(0xFFFFFFFFu); // compressed size
ds << static_cast<quint32>(0xFFFFFFFFu); // uncompressed size
ds << static_cast<quint16>(5); // name length
ds << static_cast<quint16>(extra.size()); // extra length
ds << static_cast<quint16>(0); // comment length
ds << static_cast<quint16>(0); // disk number
ds << static_cast<quint16>(0); // internal attrs
ds << static_cast<quint32>(0); // external attrs
ds << static_cast<quint32>(0xFFFFFFFFu); // local offset
ds.writeRawData("file", 4); // name
ds << static_cast<qint8>('0' + i); // name (contd.)
ds.writeRawData(extra.buffer(), extra.size());
}
qint64 centralEnd = fakeLargeFile.pos();
// zip64 end
ds << static_cast<quint32>(0x06064b50); // zip64 end magic
ds << static_cast<quint64>(44); // size of the zip64 end
ds << static_cast<quint16>(45); // version made by
ds << static_cast<quint16>(45); // version needed
ds << static_cast<quint32>(0); // disk number
ds << static_cast<quint32>(0); // central dir disk number
ds << static_cast<quint64>(2); // number of entries on disk
ds << static_cast<quint64>(2); // total number of entries
ds << static_cast<quint64>(centralEnd - centralStart); // size
ds << static_cast<quint64>(centralStart); // offset
// zip64 locator
ds << static_cast<quint32>(0x07064b50); // zip64 locator magic
ds << static_cast<quint32>(0); // disk number
ds << static_cast<quint64>(centralEnd); // offset
ds << static_cast<quint32>(1); // number of disks
// zip32 end
ds << static_cast<quint32>(0x06054b50); // end magic
ds << static_cast<quint16>(0); // disk number
ds << static_cast<quint16>(0); // central dir disk number
ds << static_cast<quint16>(2); // number of entries
ds << static_cast<quint32>(0xFFFFFFFFu); // central dir size
ds << static_cast<quint32>(0xFFFFFFFFu); // central dir offset
ds << static_cast<quint16>(0); // comment length
fakeLargeFile.close();
QuaZip fakeLargeZip("tmp/large.zip");
QVERIFY(fakeLargeZip.open(QuaZip::mdUnzip));
QCOMPARE(fakeLargeZip.getFileInfoList().size(), numFiles);
QCOMPARE(fakeLargeZip.getFileInfoList()[0].uncompressedSize,
static_cast<quint32>(0));
fakeLargeZip.close();
curDir.remove("tmp/large.zip");
}
diff --git a/qztest/testquazipfileinfo.cpp b/qztest/testquazipfileinfo.cpp
--- a/qztest/testquazipfileinfo.cpp
+++ b/qztest/testquazipfileinfo.cpp
@@ -1,108 +1,333 @@
#include "testquazipfileinfo.h"
#include "qztest.h"
#include <QByteArray>
#include <QDir>
#include <QFileInfo>
+#include <QPair>
#include <QtTest/QtTest>
#include "quazip/quazip.h"
#include "quazip/quazipfile.h"
#include "quazip/quazipfileinfo.h"
#include "quazip/quazipnewinfo.h"
+#if QT_VERSION < 0x050000
+Q_DECLARE_METATYPE(QList<qint32>);
+Q_DECLARE_METATYPE(QuaExtraFieldHash);
+#endif
+
TestQuaZipFileInfo::TestQuaZipFileInfo(QObject *parent) :
QObject(parent)
{
}
void TestQuaZipFileInfo::getNTFSTime()
{
QString zipName = "newtimes.zip";
QStringList testFiles;
testFiles << "test.txt";
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(testFiles)) {
QFAIL("Can't create test file");
}
QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
quint64 mTicks, aTicks, cTicks;
QFileInfo fileInfo("tmp/test.txt");
{
// create
QuaZip zip(zipName);
QVERIFY(zip.open(QuaZip::mdCreate));
QuaZipFile zipFile(&zip);
QDateTime lm = fileInfo.lastModified().toUTC();
QDateTime lr = fileInfo.lastRead().toUTC();
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
+ QDateTime cr = fileInfo.birthTime().toUTC();
+#else
QDateTime cr = fileInfo.created().toUTC();
+#endif
mTicks = (static_cast<qint64>(base.date().daysTo(lm.date()))
* Q_UINT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(lm.time())))
* Q_UINT64_C(10000);
aTicks = (static_cast<qint64>(base.date().daysTo(lr.date()))
* Q_UINT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(lr.time())))
* Q_UINT64_C(10000);
cTicks = (static_cast<qint64>(base.date().daysTo(cr.date()))
* Q_UINT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(cr.time())))
* Q_UINT64_C(10000);
QuaZipNewInfo newInfo("test.txt", "tmp/test.txt");
QByteArray extra(36, 0);
extra[0] = 0x0A; // magic
extra[1] = 0x00;
extra[2] = 32; // size
extra[3] = 0;
extra[4] = extra[5] = extra[6] = extra[7] = 0; // reserved
extra[8] = 0x01; // time tag
extra[9] = 0x00;
extra[10] = 24; // time tag size
extra[11] = 0;
for (int i = 12; i < 36; i += 8) {
quint64 ticks;
if (i == 12) {
ticks = mTicks;
} else if (i == 20) {
ticks = aTicks;
} else if (i == 28) {
ticks = cTicks;
} else {
QFAIL("Stupid programming bug here");
}
extra[i] = static_cast<char>(ticks);
extra[i + 1] = static_cast<char>(ticks >> 8);
extra[i + 2] = static_cast<char>(ticks >> 16);
extra[i + 3] = static_cast<char>(ticks >> 24);
extra[i + 4] = static_cast<char>(ticks >> 32);
extra[i + 5] = static_cast<char>(ticks >> 40);
extra[i + 6] = static_cast<char>(ticks >> 48);
extra[i + 7] = static_cast<char>(ticks >> 56);
}
newInfo.extraLocal = extra;
newInfo.extraGlobal = extra;
QVERIFY(zipFile.open(QIODevice::WriteOnly, newInfo));
zipFile.close();
zip.close();
}
{
// check
QuaZip zip(zipName);
QVERIFY(zip.open(QuaZip::mdUnzip));
zip.goToFirstFile();
QuaZipFileInfo64 zipFileInfo;
QVERIFY(zip.getCurrentFileInfo(&zipFileInfo));
zip.close();
QCOMPARE(zipFileInfo.getNTFSmTime(), fileInfo.lastModified());
QCOMPARE(zipFileInfo.getNTFSaTime(), fileInfo.lastRead());
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
+ QCOMPARE(zipFileInfo.getNTFScTime(), fileInfo.birthTime());
+#else
QCOMPARE(zipFileInfo.getNTFScTime(), fileInfo.created());
+#endif
}
removeTestFiles(testFiles);
curDir.remove(zipName);
}
+
+void TestQuaZipFileInfo::getExtTime_data()
+{
+ QTest::addColumn<QString>("zipName");
+ QTest::addColumn<quint8>("flags");
+ QTest::addColumn<quint16>("sizeLocal");
+ QTest::addColumn< QList<qint32> >("timesLocal");
+ QTest::addColumn<quint16>("sizeGlobal");
+ QTest::addColumn< QList<qint32> >("timesGlobal");
+ QTest::addColumn<QDateTime>("expectedModTime");
+ QTest::addColumn<QDateTime>("expectedAcTime");
+ QTest::addColumn<QDateTime>("expectedCrTime");
+ QTest::newRow("no times") << QString::fromUtf8("noTimes")
+ << quint8(0)
+ << quint16(1)
+ << QList<qint32>()
+ << quint16(1)
+ << QList<qint32>()
+ << QDateTime()
+ << QDateTime()
+ << QDateTime();
+ QTest::newRow("all times") << QString::fromUtf8("allTimes")
+ << quint8(7)
+ << quint16(13)
+ << (QList<qint32>() << 1 << 2 << 3)
+ << quint16(5)
+ << (QList<qint32>() << 1)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), Qt::UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 2), Qt::UTC)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 3), Qt::UTC);
+ QTest::newRow("no ac time") << QString::fromUtf8("noAcTime")
+ << quint8(5)
+ << quint16(9)
+ << (QList<qint32>() << 1 << 3)
+ << quint16(5)
+ << (QList<qint32>() << 1)
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), Qt::UTC)
+ << QDateTime()
+ << QDateTime(QDate(1970, 1, 1), QTime(0, 0, 3), Qt::UTC);
+ QTest::newRow("negativeTime") << QString::fromUtf8("negativeTime")
+ << quint8(1)
+ << quint16(5)
+ << (QList<qint32>() << -1)
+ << quint16(5)
+ << (QList<qint32>() << -1)
+ << QDateTime(QDate(1969, 12, 31), QTime(23, 59, 59), Qt::UTC)
+ << QDateTime()
+ << QDateTime();
+}
+
+static QByteArray makeExtTimeField(quint16 size, quint8 flags, const QList<qint32> &times)
+{
+ if (size == 0)
+ return QByteArray();
+ const quint16 EXT_TIME_MAGIC = 0x5455;
+ QBuffer buffer;
+ buffer.open(QBuffer::WriteOnly);
+ QDataStream localStream(&buffer);
+ localStream.setByteOrder(QDataStream::LittleEndian);
+ localStream << EXT_TIME_MAGIC;
+ localStream << size;
+ localStream << flags;
+ Q_FOREACH(qint32 time, times) {
+ localStream << time;
+ }
+ return buffer.buffer();
+}
+
+void TestQuaZipFileInfo::getExtTime()
+{
+ QFETCH(QString, zipName);
+ QFETCH(quint8, flags);
+ QFETCH(quint16, sizeLocal);
+ QFETCH(QList<qint32>, timesLocal);
+ QFETCH(quint16, sizeGlobal);
+ QFETCH(QList<qint32>, timesGlobal);
+ QFETCH(QDateTime, expectedModTime);
+ QFETCH(QDateTime, expectedAcTime);
+ QFETCH(QDateTime, expectedCrTime);
+ QStringList fileNames;
+ QString fileName = QString::fromLatin1("aFile.txt");
+ fileNames << fileName;
+ {
+ createTestFiles(fileNames);
+ QuaZip testZip("tmp/" + zipName);
+ testZip.open(QuaZip::mdCreate);
+ QuaZipFile file(&testZip);
+ QuaZipNewInfo newInfo(fileName, "tmp/" + fileName);
+ newInfo.extraLocal = makeExtTimeField(sizeLocal, flags, timesLocal);
+ newInfo.extraGlobal = makeExtTimeField(sizeGlobal, flags, timesGlobal);
+ file.open(QIODevice::WriteOnly, newInfo);
+ file.close();
+ testZip.close();
+ }
+ removeTestFiles(fileNames);
+ QuaZip zip("tmp/" + zipName);
+ QVERIFY(zip.open(QuaZip::mdUnzip));
+ QVERIFY(zip.goToFirstFile());
+ QuaZipFileInfo64 fileInfo;
+ QVERIFY(zip.getCurrentFileInfo(&fileInfo));
+ QuaZipFile zipFile(&zip);
+ QVERIFY(zipFile.open(QIODevice::ReadOnly));
+ QDateTime actualGlobalModTime = fileInfo.getExtModTime();
+ QDateTime actualLocalModTime = zipFile.getExtModTime();
+ QDateTime actualLocalAcTime = zipFile.getExtAcTime();
+ QDateTime actualLocalCrTime = zipFile.getExtCrTime();
+ zipFile.close();
+ QCOMPARE(actualGlobalModTime, expectedModTime);
+ QCOMPARE(actualLocalModTime, expectedModTime);
+ QCOMPARE(actualLocalAcTime, expectedAcTime);
+ QCOMPARE(actualLocalCrTime, expectedCrTime);
+ zip.close();
+ QDir("tmp").remove(zipName);
+}
+
+void TestQuaZipFileInfo::getExtTime_issue43()
+{
+ // Test original GitHub issue, just in case.
+ // (The test above relies on manual ZIP generation, which isn't perfect.)
+ QuaZip zip(":/test_files/issue43_cant_get_dates.zip");
+ QVERIFY(zip.open(QuaZip::mdUnzip));
+ zip.goToFirstFile();
+ QuaZipFileInfo64 zipFileInfo;
+ QVERIFY(zip.getCurrentFileInfo(&zipFileInfo));
+ zip.goToFirstFile();
+ QuaZipFile zipFile(&zip);
+ QVERIFY(zipFile.open(QIODevice::ReadOnly));
+ QDateTime actualGlobalModTime = zipFileInfo.getExtModTime();
+ QDateTime actualLocalModTime = zipFile.getExtModTime();
+ QDateTime actualLocalAcTime = zipFile.getExtAcTime();
+ QDateTime actualLocalCrTime = zipFile.getExtCrTime();
+ zip.close();
+ QDateTime extModTime(QDate(2019, 7, 2), QTime(15, 43, 47), Qt::UTC);
+ QDateTime extAcTime = extModTime;
+ QDateTime extCrTime = extModTime;
+ QCOMPARE(actualGlobalModTime, extModTime);
+ QCOMPARE(actualLocalModTime, extModTime);
+ QCOMPARE(actualLocalAcTime, extAcTime);
+ QCOMPARE(actualLocalCrTime, extCrTime);
+}
+
+void TestQuaZipFileInfo::parseExtraField_data()
+{
+ QTest::addColumn<QByteArray>("extraField");
+ QTest::addColumn<QuaExtraFieldHash>("expected");
+ QTest::newRow("empty")
+ << QByteArray()
+ << QuaExtraFieldHash();
+ {
+ QuaExtraFieldHash oneZeroIdWithNoData;
+ oneZeroIdWithNoData[0] = QList<QByteArray>() << QByteArray();
+ QTest::newRow("one zero ID with no data")
+ << QByteArray("\x00\x00\x00\x00", 4)
+ << oneZeroIdWithNoData;
+ }
+ {
+ QuaExtraFieldHash oneZeroIdWithData;
+ oneZeroIdWithData[0] = QList<QByteArray>() << QByteArray("DATA", 4);
+ QTest::newRow("one zero ID with data")
+ << QByteArray("\x00\x00\x04\x00" "DATA", 8)
+ << oneZeroIdWithData;
+ }
+ {
+ QuaExtraFieldHash oneNonZeroIdWithData;
+ oneNonZeroIdWithData[1] = QList<QByteArray>() << QByteArray("DATA", 4);
+ QTest::newRow("one non zero ID with data")
+ << QByteArray("\x01\x00\x04\x00" "DATA", 8)
+ << oneNonZeroIdWithData;
+ }
+ {
+ QuaExtraFieldHash severalDifferentIDs;
+ severalDifferentIDs[0] = QList<QByteArray>() << QByteArray("DATA0", 5);
+ severalDifferentIDs[1] = QList<QByteArray>() << QByteArray("DATA1", 5);
+ QTest::newRow("two IDs")
+ << QByteArray("\x00\x00\x05\x00" "DATA0" "\x01\x00\x05\x00" "DATA1", 18)
+ << severalDifferentIDs;
+ }
+ {
+ QuaExtraFieldHash repeatedID;
+ repeatedID[0] = QList<QByteArray>() << QByteArray("DATA0", 5) << QByteArray("DATA1", 5);
+ QTest::newRow("repeated ID")
+ << QByteArray("\x00\x00\x05\x00" "DATA0" "\x00\x00\x05\x00" "DATA1", 18)
+ << repeatedID;
+ }
+ {
+ QuaExtraFieldHash largeID;
+ largeID[0x0102] = QList<QByteArray>() << QByteArray("DATA", 4);
+ QTest::newRow("large ID")
+ << QByteArray("\x02\x01\x04\x00" "DATA", 8)
+ << largeID;
+ }
+ {
+ QuaExtraFieldHash largeData;
+ largeData[0] = QList<QByteArray>() << QByteArray(65535, 'x');
+ QTest::newRow("large ID")
+ << (QByteArray("\x00\x00\xff\xff", 4) + QByteArray(65535, 'x'))
+ << largeData;
+ }
+ QTest::newRow("only 1 byte") << QByteArray("\x00", 1) << QuaExtraFieldHash();
+ QTest::newRow("only 2 bytes") << QByteArray("\x00\x00", 2) << QuaExtraFieldHash();
+ QTest::newRow("only 3 bytes") << QByteArray("\x00\x00\x00", 3) << QuaExtraFieldHash();
+ QTest::newRow("truncated data") << QByteArray("\x00\x00\x02\x00\x00", 5) << QuaExtraFieldHash();
+}
+
+void TestQuaZipFileInfo::parseExtraField()
+{
+ QFETCH(QByteArray, extraField);
+ QFETCH(QuaExtraFieldHash, expected);
+ QuaExtraFieldHash actual = QuaZipFileInfo64::parseExtraField(extraField);
+ QCOMPARE(actual, expected);
+}
diff --git a/qztest/testquazipfileinfo.h b/qztest/testquazipfileinfo.h
--- a/qztest/testquazipfileinfo.h
+++ b/qztest/testquazipfileinfo.h
@@ -1,15 +1,20 @@
#ifndef TESTQUAZIPFILEINFO_H
#define TESTQUAZIPFILEINFO_H
#include <QObject>
class TestQuaZipFileInfo : public QObject
{
Q_OBJECT
public:
explicit TestQuaZipFileInfo(QObject *parent = 0);
private slots:
void getNTFSTime();
+ void getExtTime_data();
+ void getExtTime();
+ void getExtTime_issue43();
+ void parseExtraField_data();
+ void parseExtraField();
};
#endif // TESTQUAZIPFILEINFO_H
diff --git a/qztest/testquazipnewinfo.cpp b/qztest/testquazipnewinfo.cpp
--- a/qztest/testquazipnewinfo.cpp
+++ b/qztest/testquazipnewinfo.cpp
@@ -1,146 +1,150 @@
#include "testquazipnewinfo.h"
#include "qztest.h"
#include <QDir>
#include <QFileInfo>
#include <QtTest/QtTest>
#include <quazip/quazip.h>
#include <quazip/quazipfile.h>
#include <quazip/quazipnewinfo.h>
#include <quazip/quazipfileinfo.h>
TestQuaZipNewInfo::TestQuaZipNewInfo(QObject *parent) :
QObject(parent)
{
}
void TestQuaZipNewInfo::setFileNTFSTimes()
{
QString zipName = "newtimes.zip";
QStringList testFiles;
testFiles << "test.txt";
QDir curDir;
if (curDir.exists(zipName)) {
if (!curDir.remove(zipName))
QFAIL("Can't remove zip file");
}
if (!createTestFiles(testFiles)) {
QFAIL("Can't create test file");
}
QDateTime base(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
quint64 mTicks, aTicks, cTicks;
{
// create
QuaZip zip(zipName);
QVERIFY(zip.open(QuaZip::mdCreate));
QuaZipFile zipFile(&zip);
QFileInfo fileInfo("tmp/test.txt");
QDateTime lm = fileInfo.lastModified().toUTC();
QDateTime lr = fileInfo.lastRead().toUTC();
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
+ QDateTime cr = fileInfo.birthTime().toUTC();
+#else
QDateTime cr = fileInfo.created().toUTC();
+#endif
mTicks = (static_cast<qint64>(base.date().daysTo(lm.date()))
* Q_UINT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(lm.time())))
* Q_UINT64_C(10000);
aTicks = (static_cast<qint64>(base.date().daysTo(lr.date()))
* Q_UINT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(lr.time())))
* Q_UINT64_C(10000);
cTicks = (static_cast<qint64>(base.date().daysTo(cr.date()))
* Q_UINT64_C(86400000)
+ static_cast<qint64>(base.time().msecsTo(cr.time())))
* Q_UINT64_C(10000);
QuaZipNewInfo newInfo("test.txt", "tmp/test.txt");
newInfo.setFileNTFSTimes("tmp/test.txt");
QVERIFY(zipFile.open(QIODevice::WriteOnly, newInfo));
zipFile.close();
zip.close();
}
{
// check
QuaZip zip(zipName);
QVERIFY(zip.open(QuaZip::mdUnzip));
zip.goToFirstFile();
QuaZipFileInfo64 fileInfo;
QVERIFY(zip.getCurrentFileInfo(&fileInfo));
zip.close();
QByteArray &extra = fileInfo.extra;
bool ntfsFound = false;
int timesFound = 0;
for (int i = 0; i <= extra.size() - 4; ) {
unsigned type = static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i)))
| (static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i + 1))) << 8);
i += 2;
unsigned length = static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i)))
| (static_cast<unsigned>(static_cast<unsigned char>(
extra.at(i + 1))) << 8);
i += 2;
if (type == 0x000Au && length >= 32) {
ntfsFound = true;
i += 4; // reserved
while (i <= extra.size() - 4) {
unsigned tag = static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i)))
| (static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i + 1)))
<< 8);
i += 2;
unsigned tagsize = static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i)))
| (static_cast<unsigned>(
static_cast<unsigned char>(extra.at(i + 1)))
<< 8);
i += 2;
QCOMPARE(tagsize, static_cast<unsigned>(24));
if (tag == 0x0001u && tagsize >= 24) {
for (int timesPos = i;
i < timesPos + 24;
i += 8, tagsize -= 8) {
quint64 time = static_cast<quint64>(
static_cast<unsigned char>(extra.at(i)))
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 1))) << 8)
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 2))) << 16)
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 3))) << 24)
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 4))) << 32)
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 5))) << 40)
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 6))) << 48)
| (static_cast<quint64>(static_cast<unsigned char>(
extra.at(i + 7))) << 56);
++timesFound;
if (i - timesPos == 0) {
QCOMPARE(time, mTicks);
} else if (i - timesPos == 8) {
QCOMPARE(time, aTicks);
} else if (i - timesPos == 16) {
QCOMPARE(time, cTicks);
} else {
QFAIL("Wrong position");
}
}
i += tagsize;
} else {
i += tagsize;
}
}
} else {
i += length;
}
}
QVERIFY(ntfsFound);
QCOMPARE(timesFound, 3);
}
removeTestFiles(testFiles);
curDir.remove(zipName);
}
diff --git a/test.diff b/test.diff
--- a/test.diff
+++ b/test.diff
@@ -1,77 +1,140 @@
diff -u a/qztest/qztest.cpp b/qztest/qztest.cpp
--- a/qztest/qztest.cpp 2023-05-31 17:48:37.376339390 +0300
+++ b/qztest/qztest.cpp 2019-09-12 15:40:16.889104000 +0300
@@ -25,10 +25,6 @@
#include "qztest.h"
#include "testquazip.h"
#include "testquazipfile.h"
-#include "testquachecksum32.h"
-#include "testjlcompress.h"
-#include "testquazipdir.h"
-#include "testquagzipfile.h"
#include "testquaziodevice.h"
#include "testquazipnewinfo.h"
#include "testquazipfileinfo.h"
-@@ -201,26 +197,10 @@
+@@ -71,7 +67,11 @@
+ }
+ if (size == -1) {
+ QTextStream testStream(&testFile);
++#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
+ testStream << "This is a test file named " << fileName << endl;
++#else
++ testStream << "This is a test file named " << fileName << Qt::endl;
++#endif
+ } else {
+ for (int i = 0; i < size; ++i) {
+ testFile.putChar(static_cast<char>('0' + i % 10));
+@@ -201,26 +201,10 @@
err = qMax(err, QTest::qExec(&testQuaZipFile, app.arguments()));
}
{
- TestQuaChecksum32 testQuaChecksum32;
- err = qMax(err, QTest::qExec(&testQuaChecksum32, app.arguments()));
- }
- {
- TestJlCompress testJlCompress;
- err = qMax(err, QTest::qExec(&testJlCompress, app.arguments()));
- }
- {
- TestQuaZipDir testQuaZipDir;
- err = qMax(err, QTest::qExec(&testQuaZipDir, app.arguments()));
- }
- {
TestQuaZIODevice testQuaZIODevice;
err = qMax(err, QTest::qExec(&testQuaZIODevice, app.arguments()));
}
{
- TestQuaGzipFile testQuaGzipFile;
- err = qMax(err, QTest::qExec(&testQuaGzipFile, app.arguments()));
- }
- {
TestQuaZipNewInfo testQuaZipNewInfo;
err = qMax(err, QTest::qExec(&testQuaZipNewInfo, app.arguments()));
}
diff -u a/qztest/testjlcompress.cpp b/qztest/testjlcompress.cpp
--- a/qztest/testjlcompress.cpp 2023-05-31 17:48:37.376339390 +0300
+++ b/qztest/testjlcompress.cpp 2019-09-12 15:40:16.889104000 +0300
-@@ -31,7 +31,7 @@
+@@ -32,7 +32,7 @@
#include <QtTest/QtTest>
-#include <quazip/JlCompress.h>
+#include "JlCompress.h"
#ifdef Q_OS_WIN
#include <windows.h>
diff -u a/qztest/testquazip.cpp b/qztest/testquazip.cpp
--- a/qztest/testquazip.cpp 2023-05-31 17:48:37.380339356 +0300
+++ b/qztest/testquazip.cpp 2019-09-12 15:40:16.889104000 +0300
@@ -40,7 +40,7 @@
#include <QtTest/QtTest>
#include <quazip/quazip.h>
-#include <quazip/JlCompress.h>
+#include "JlCompress.h"
void TestQuaZip::getFileList_data()
{
diff -u a/qztest/testquazipfile.cpp b/qztest/testquazipfile.cpp
--- a/qztest/testquazipfile.cpp 2023-05-31 17:48:37.380339356 +0300
+++ b/qztest/testquazipfile.cpp 2021-11-26 15:54:40.415006290 +0300
@@ -26,7 +26,7 @@
#include "qztest.h"
-#include <quazip/JlCompress.h>
+#include "JlCompress.h"
#include <quazip/quazipfile.h>
#include <quazip/quazip.h>
+@@ -35,6 +35,7 @@
+ #include <QStringList>
+
+ #include <QtTest/QtTest>
++#include <QRandomGenerator>
+
+ void TestQuaZipFile::zipUnzip_data()
+ {
+@@ -307,11 +308,11 @@
+ QCOMPARE(zipFile.pos(), (qint64) 1);
+ QByteArray buffer(size / 2 - 1, '\0');
+ for (int i = 0; i < buffer.size(); ++i)
+- buffer[i] = static_cast<char>(qrand());
++ buffer[i] = static_cast<char>(QRandomGenerator::global()->generate());
+ zipFile.write(buffer);
+ QCOMPARE(zipFile.pos(), qint64(size / 2));
+ for (int i = 0; i < size - size / 2; ++i) {
+- zipFile.putChar(static_cast<char>(qrand()));
++ zipFile.putChar(static_cast<char>(QRandomGenerator::global()->generate()));
+ }
+ QCOMPARE(zipFile.pos(), qint64(size));
+ }
+diff -u a/qztest/JlCompress.h b/qztest/JlCompress.h
+--- a/qztest/JlCompress.h 2020-05-24 15:02:43.000000000 +0300
++++ b/qztest/JlCompress.h 2023-05-31 19:13:44.969948540 +0300
+@@ -26,9 +26,9 @@
+ see quazip/(un)zip.h files for details. Basically it's the zlib license.
+ */
+
+-#include "quazip.h"
+-#include "quazipfile.h"
+-#include "quazipfileinfo.h"
++#include "quazip/quazip.h"
++#include "quazip/quazipfile.h"
++#include "quazip/quazipfileinfo.h"
+ #include <QtCore/QString>
+ #include <QtCore/QDir>
+ #include <QtCore/QFileInfo>
+diff -u a/qztest/JlCompress.cpp b/qztest/JlCompress.cpp
+--- a/qztest/JlCompress.cpp 2020-05-24 15:02:43.000000000 +0300
++++ b/qztest/JlCompress.cpp 2023-05-31 19:14:52.585386324 +0300
+@@ -261,7 +261,7 @@
+ }
+
+ bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) {
+- return compressDir(fileCompressed, dir, recursive, 0);
++ return compressDir(fileCompressed, dir, recursive, {});
+ }
+
+ bool JlCompress::compressDir(QString fileCompressed, QString dir,
+
diff --git a/zip.diff b/zip.diff
--- a/zip.diff
+++ b/zip.diff
@@ -1,430 +1,442 @@
diff -u a/quazip/unzip.c b/quazip/unzip.c
--- a/quazip/unzip.c 2023-05-31 17:48:37.372339423 +0300
+++ b/quazip/unzip.c 2021-11-26 15:50:18.266174865 +0300
@@ -140,10 +140,6 @@
char *read_buffer; /* internal buffer for compressed data */
z_stream stream; /* zLib stream structure for inflate */
-#ifdef HAVE_BZIP2
- bz_stream bstream; /* bzLib stream structure for bziped */
-#endif
-
ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
uLong stream_initialised; /* flag set if stream structure is initialised*/
-@@ -1433,9 +1429,6 @@
+@@ -1446,9 +1442,6 @@
err=UNZ_BADZIPFILE;
if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
-/* #ifdef HAVE_BZIP2 */
- (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
-/* #endif */
(s->cur_file_info.compression_method!=Z_DEFLATED))
err=UNZ_BADZIPFILE;
-@@ -1540,9 +1533,6 @@
+@@ -1553,9 +1546,6 @@
}
if ((s->cur_file_info.compression_method!=0) &&
-/* #ifdef HAVE_BZIP2 */
- (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
-/* #endif */
(s->cur_file_info.compression_method!=Z_DEFLATED))
err=UNZ_BADZIPFILE;
-@@ -1557,33 +1547,7 @@
+@@ -1570,33 +1560,7 @@
pfile_in_zip_read_info->stream.total_out = 0;
- if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))
- {
-#ifdef HAVE_BZIP2
- pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
- pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
- pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
- pfile_in_zip_read_info->bstream.state = (voidpf)0;
-
- pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
- pfile_in_zip_read_info->stream.zfree = (free_func)0;
- pfile_in_zip_read_info->stream.opaque = (voidpf)0;
- pfile_in_zip_read_info->stream.next_in = (voidpf)0;
- pfile_in_zip_read_info->stream.avail_in = 0;
-
- err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
- if (err == Z_OK)
- pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
- else
- {
- TRYFREE(pfile_in_zip_read_info);
- return err;
- }
-#else
- pfile_in_zip_read_info->raw=1;
-#endif
- }
- else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
+ if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
{
pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
pfile_in_zip_read_info->stream.zfree = (free_func)0;
-@@ -1803,49 +1767,6 @@
+@@ -1816,49 +1780,6 @@
pfile_in_zip_read_info->stream.total_out += uDoCopy;
iRead += uDoCopy;
}
- else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
- {
-#ifdef HAVE_BZIP2
- uLong uTotalOutBefore,uTotalOutAfter;
- const Bytef *bufBefore;
- uLong uOutThis;
-
- pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in;
- pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in;
- pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in;
- pfile_in_zip_read_info->bstream.total_in_hi32 = 0;
- pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out;
- pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out;
- pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
- pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
-
- uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
- bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;
-
- err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
-
- uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
- uOutThis = uTotalOutAfter-uTotalOutBefore;
-
- pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
-
- pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));
- pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
- iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
-
- pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in;
- pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in;
- pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32;
- pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out;
- pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
- pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
-
- if (err==BZ_STREAM_END)
- return (iRead==0) ? UNZ_EOF : iRead;
- if (err!=BZ_OK)
- break;
-#endif
- } /* end Z_BZIP2ED */
else
{
uInt uAvailOutBefore,uAvailOutAfter;
-@@ -2031,10 +1952,6 @@
+@@ -2044,10 +1965,6 @@
pfile_in_zip_read_info->read_buffer = NULL;
if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
inflateEnd(&pfile_in_zip_read_info->stream);
-#ifdef HAVE_BZIP2
- else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
- BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
-#endif
pfile_in_zip_read_info->stream_initialised = 0;
diff -u a/quazip/unzip.h b/quazip/unzip.h
--- a/quazip/unzip.h 2023-05-31 17:48:37.372339423 +0300
+++ b/quazip/unzip.h 2019-09-12 15:40:20.781101000 +0300
@@ -60,12 +60,6 @@
#include "ioapi.h"
#endif
-#ifdef HAVE_BZIP2
-#include "bzlib.h"
-#endif
-
-#define Z_BZIP2ED 12
-
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
diff -u a/quazip/zip.c b/quazip/zip.c
--- a/quazip/zip.c 2023-05-31 17:48:37.372339423 +0300
+++ b/quazip/zip.c 2021-11-26 15:53:25.805832359 +0300
-@@ -140,9 +140,6 @@
+@@ -141,9 +141,6 @@
typedef struct
{
z_stream stream; /* zLib stream structure for inflate */
-#ifdef HAVE_BZIP2
- bz_stream bstream; /* bzLib stream structure for bziped */
-#endif
int stream_initialised; /* 1 is stream is initialised */
uInt pos_in_buffered_data; /* last written byte in buffered_data */
-@@ -1101,13 +1098,8 @@
+@@ -1104,13 +1101,8 @@
if (file == NULL)
return ZIP_PARAMERROR;
-#ifdef HAVE_BZIP2
- if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED))
- return ZIP_PARAMERROR;
-#else
if ((method!=0) && (method!=Z_DEFLATED))
return ZIP_PARAMERROR;
-#endif
zi = (zip64_internal*)file;
-@@ -1231,16 +1223,6 @@
+@@ -1236,16 +1228,6 @@
err = Write_LocalFileHeader(zi, filename, size_extrafield_local,
extrafield_local, version_to_extract);
-#ifdef HAVE_BZIP2
- zi->ci.bstream.avail_in = (uInt)0;
- zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
- zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
- zi->ci.bstream.total_in_hi32 = 0;
- zi->ci.bstream.total_in_lo32 = 0;
- zi->ci.bstream.total_out_hi32 = 0;
- zi->ci.bstream.total_out_lo32 = 0;
-#endif
-
zi->ci.stream.avail_in = (uInt)0;
zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
zi->ci.stream.next_out = zi->ci.buffered_data;
-@@ -1248,11 +1230,7 @@
+@@ -1253,11 +1235,7 @@
zi->ci.stream.total_out = 0;
zi->ci.stream.data_type = Z_BINARY;
-#ifdef HAVE_BZIP2
- if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
-#else
if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
-#endif
{
if(zi->ci.method == Z_DEFLATED)
{
-@@ -1268,19 +1246,6 @@
+@@ -1273,19 +1251,6 @@
if (err==Z_OK)
zi->ci.stream_initialised = Z_DEFLATED;
}
- else if(zi->ci.method == Z_BZIP2ED)
- {
-#ifdef HAVE_BZIP2
- /* Init BZip stuff here */
- zi->ci.bstream.bzalloc = 0;
- zi->ci.bstream.bzfree = 0;
- zi->ci.bstream.opaque = (voidpf)0;
-
- err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35);
- if(err == BZ_OK)
- zi->ci.stream_initialised = Z_BZIP2ED;
-#endif
- }
}
-@@ -1425,20 +1390,8 @@
+@@ -1430,20 +1395,8 @@
err = ZIP_ERRNO;
zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
-
-#ifdef HAVE_BZIP2
- if(zi->ci.method == Z_BZIP2ED)
- {
- zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32;
- zi->ci.bstream.total_in_lo32 = 0;
- zi->ci.bstream.total_in_hi32 = 0;
- }
- else
-#endif
- {
- zi->ci.totalUncompressedData += zi->ci.stream.total_in;
- zi->ci.stream.total_in = 0;
- }
+ zi->ci.totalUncompressedData += zi->ci.stream.total_in;
+ zi->ci.stream.total_in = 0;
zi->ci.pos_in_buffered_data = 0;
-@@ -1460,89 +1413,51 @@
+@@ -1465,89 +1418,51 @@
zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
-#ifdef HAVE_BZIP2
- if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw))
- {
- zi->ci.bstream.next_in = (void*)buf;
- zi->ci.bstream.avail_in = len;
- err = BZ_RUN_OK;
+ zi->ci.stream.next_in = (Bytef*)buf;
+ zi->ci.stream.avail_in = len;
- while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0))
- {
- if (zi->ci.bstream.avail_out == 0)
+ while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+ {
+ if (zi->ci.stream.avail_out == 0)
{
- if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
- err = ZIP_ERRNO;
- zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
- zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
}
- if(err != BZ_RUN_OK)
- break;
+ if(err != ZIP_OK)
+ break;
- if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
{
- uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32;
-/* uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; */
- err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN);
-
- zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ;
+ uInt uAvailOutBefore = zi->ci.stream.avail_out;
+ err=deflate(&zi->ci.stream, Z_NO_FLUSH);
+ zi->ci.pos_in_buffered_data += uAvailOutBefore - zi->ci.stream.avail_out;
}
- }
-
- if(err == BZ_RUN_OK)
- err = ZIP_OK;
- }
- else
-#endif
- {
- zi->ci.stream.next_in = (Bytef*)buf;
- zi->ci.stream.avail_in = len;
-
- while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
- {
- if (zi->ci.stream.avail_out == 0)
- {
- if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
- err = ZIP_ERRNO;
- zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
- zi->ci.stream.next_out = zi->ci.buffered_data;
- }
-
-
- if(err != ZIP_OK)
- break;
-
- if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
- {
- uInt uAvailOutBefore = zi->ci.stream.avail_out;
- err=deflate(&zi->ci.stream, Z_NO_FLUSH);
- zi->ci.pos_in_buffered_data += uAvailOutBefore - zi->ci.stream.avail_out;
- }
- else
- {
- uInt copy_this,i;
- if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
- copy_this = zi->ci.stream.avail_in;
- else
- copy_this = zi->ci.stream.avail_out;
-
- for (i = 0; i < copy_this; i++)
- *(((char*)zi->ci.stream.next_out)+i) =
- *(((const char*)zi->ci.stream.next_in)+i);
- {
- zi->ci.stream.avail_in -= copy_this;
- zi->ci.stream.avail_out-= copy_this;
- zi->ci.stream.next_in+= copy_this;
- zi->ci.stream.next_out+= copy_this;
- zi->ci.stream.total_in+= copy_this;
- zi->ci.stream.total_out+= copy_this;
- zi->ci.pos_in_buffered_data += copy_this;
- }
- }
- }/* while(...) */
- }
+ else
+ {
+ uInt copy_this,i;
+ if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+ copy_this = zi->ci.stream.avail_in;
+ else
+ copy_this = zi->ci.stream.avail_out;
+
+ for (i = 0; i < copy_this; i++)
+ *(((char*)zi->ci.stream.next_out)+i) =
+ *(((const char*)zi->ci.stream.next_in)+i);
+ {
+ zi->ci.stream.avail_in -= copy_this;
+ zi->ci.stream.avail_out-= copy_this;
+ zi->ci.stream.next_in+= copy_this;
+ zi->ci.stream.next_out+= copy_this;
+ zi->ci.stream.total_in+= copy_this;
+ zi->ci.stream.total_out+= copy_this;
+ zi->ci.pos_in_buffered_data += copy_this;
+ }
+ }
+ }/* while(...) */
return err;
}
-@@ -1585,32 +1500,6 @@
+@@ -1590,32 +1505,6 @@
zi->ci.pos_in_buffered_data += uAvailOutBefore - zi->ci.stream.avail_out;
}
}
- else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
- {
-#ifdef HAVE_BZIP2
- err = BZ_FINISH_OK;
- while (err==BZ_FINISH_OK)
- {
- uLong uTotalOutBefore;
- if (zi->ci.bstream.avail_out == 0)
- {
- if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
- err = ZIP_ERRNO;
- zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
- zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
- }
- uTotalOutBefore = zi->ci.bstream.total_out_lo32;
- err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH);
- if(err == BZ_STREAM_END)
- err = Z_STREAM_END;
-
- zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore);
- }
-
- if(err == BZ_FINISH_OK)
- err = ZIP_OK;
-#endif
- }
if (err==Z_STREAM_END)
err=ZIP_OK; /* this is normal */
diff -u a/quazip/zip.h b/quazip/zip.h
--- a/quazip/zip.h 2023-05-31 17:48:37.376339390 +0300
+++ b/quazip/zip.h 2019-09-12 15:40:20.777101000 +0300
@@ -50,8 +50,6 @@
extern "C" {
#endif
-//#define HAVE_BZIP2
-
#ifndef _ZLIB_H
- #include "zlib.h"
+ #include <zlib.h>
#endif
@@ -60,12 +58,6 @@
#include "ioapi.h"
#endif
-#ifdef HAVE_BZIP2
-#include "bzlib.h"
-#endif
-
-#define Z_BZIP2ED 12
-
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
+diff -u a/quazip/quazipfileinfo.cpp b/quazip/quazipfileinfo.cpp
+--- a/quazip/quazipfileinfo.cpp 2020-05-24 15:02:43.000000000 +0300
++++ b/quazip/quazipfileinfo.cpp 2023-05-31 19:14:19.169664155 +0300
+@@ -28,7 +28,7 @@
+
+ static QFile::Permissions permissionsFromExternalAttr(quint32 externalAttr) {
+ quint32 uPerm = (externalAttr & 0xFFFF0000u) >> 16;
+- QFile::Permissions perm = 0;
++ QFile::Permissions perm {};
+ if ((uPerm & 0400) != 0)
+ perm |= QFile::ReadOwner;
+ if ((uPerm & 0200) != 0)

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 11, 8:41 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
127153

Event Timeline