CMake build system, big pile of libs: bspatch, quazip, java, the launcher
This commit is contained in:
parent
d6d5c86a73
commit
b1d00fce8d
5
.gitignore
vendored
5
.gitignore
vendored
@ -1 +1,6 @@
|
||||
Thumbs.db
|
||||
.kdev4
|
||||
MultiMC5.kdev4
|
||||
build
|
||||
resources/CMakeFiles
|
||||
resources/MultiMCLauncher.jar
|
||||
|
132
CMakeLists.txt
Normal file
132
CMakeLists.txt
Normal file
@ -0,0 +1,132 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
project(multimc5)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
|
||||
#### Check for machine endianness ####
|
||||
INCLUDE(TestBigEndian)
|
||||
TEST_BIG_ENDIAN(BIGENDIAN)
|
||||
IF(${BIGENDIAN})
|
||||
ADD_DEFINITIONS(-DMULTIMC_BIG_ENDIAN)
|
||||
ENDIF(${BIGENDIAN})
|
||||
|
||||
|
||||
#### Find the required Qt parts ####
|
||||
find_package(Qt5Widgets)
|
||||
#find_package(Qt5Declarative)
|
||||
|
||||
include_directories(${Qt5Widgets_INCLUDE_DIRS})
|
||||
|
||||
# find ZLIB for quazip
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
# Find boost.
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
MESSAGE(STATUS "** Finding Boost...")
|
||||
find_package(Boost 1.46.0 REQUIRED)
|
||||
MESSAGE(STATUS "** Boost Include: ${Boost_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "** Boost Libraries: ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
# Include boost.
|
||||
include_directories("${Boost_INCLUDE_DIRS}")
|
||||
|
||||
# Add quazip
|
||||
add_subdirectory(quazip)
|
||||
|
||||
# Add bspatch
|
||||
add_subdirectory(patchlib)
|
||||
include_directories(patchlib)
|
||||
|
||||
# add the java launcher
|
||||
add_subdirectory(launcher)
|
||||
|
||||
IF(UNIX)
|
||||
# assume GCC, add C++0x/C++11 stuff
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
ELSEIF(MINGW)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
|
||||
ENDIF()
|
||||
|
||||
# Set the path where CMake will look for modules.
|
||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}")
|
||||
|
||||
|
||||
set(MultiMC_VERSION_MAJOR 5)
|
||||
set(MultiMC_VERSION_MINOR 0)
|
||||
set(MultiMC_VERSION_REV 0)
|
||||
|
||||
SET(MultiMC_VERSION_BUILD 0 CACHE STRING "Build number.")
|
||||
message(STATUS "MultiMC build #${MultiMC_VERSION_BUILD}")
|
||||
|
||||
IF (DEFINED MultiMC_BUILD_TAG)
|
||||
message(STATUS "Build tag: ${MultiMC_BUILD_TAG}")
|
||||
ELSE ()
|
||||
message(STATUS "No build tag specified.")
|
||||
ENDIF ()
|
||||
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
set (MultiMC_ARCH "x64"
|
||||
CACHE STRING "Architecture we're building for.")
|
||||
else()
|
||||
set (MultiMC_ARCH "x86"
|
||||
CACHE STRING "Architecture we're building for.")
|
||||
endif()
|
||||
message (STATUS "Architecture is ${MultiMC_ARCH}")
|
||||
|
||||
SET(MultiMC_Extra_Label "")
|
||||
|
||||
IF (WIN32)
|
||||
SET(MultiMC_JOB_NAME "MultiMC4Windows" CACHE STRING "Jenkins job name.")
|
||||
ELSEIF(UNIX AND APPLE)
|
||||
SET(MultiMC_JOB_NAME "MultiMC4OSX" CACHE STRING "Jenkins job name.")
|
||||
# This is here because the scheme doesn't exactly apply to every kind of build...
|
||||
SET(MultiMC_Extra_Label ",label=osx")
|
||||
ELSE()
|
||||
SET(MultiMC_JOB_NAME "MultiMC4Linux" CACHE STRING "Jenkins job name.")
|
||||
ENDIF()
|
||||
|
||||
SET(MultiMC_JOB_URL "http://ci.forkk.net/job/${MultiMC_JOB_NAME}/arch=${MultiMC_ARCH}${MultiMC_Extra_Label}/"
|
||||
CACHE STRING "URL of the jenkins job to pull updates from.")
|
||||
message(STATUS "Job URL: ${MultiMC_JOB_URL}")
|
||||
|
||||
configure_file("${PROJECT_SOURCE_DIR}/config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/config.h")
|
||||
|
||||
|
||||
SET(MULTIMC_SOURCES
|
||||
main.cpp
|
||||
gui/mainwindow.cpp
|
||||
data/instancebase.cpp
|
||||
util/pathutils.cpp
|
||||
|
||||
java/javautils.cpp
|
||||
java/annotations.cpp
|
||||
)
|
||||
|
||||
SET(MULTIMC_HEADERS
|
||||
gui/mainwindow.h
|
||||
data/instancebase.h
|
||||
util/pathutils.h
|
||||
multimc_pragma.h
|
||||
|
||||
java/annotations.h
|
||||
java/classfile.h
|
||||
java/constants.h
|
||||
java/endian.h
|
||||
java/errors.h
|
||||
java/javautils.h
|
||||
java/membuffer.h
|
||||
)
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(resources/MultiMCLauncher.jar GENERATED)
|
||||
|
||||
QT5_WRAP_UI(MULTIMC_UI gui/mainwindow.ui)
|
||||
QT5_ADD_RESOURCES(MULTIMC_QRC multimc.qrc)
|
||||
|
||||
add_executable(multimc5 ${MULTIMC_SOURCES} ${MULTIMC_HEADERS} ${MULTIMC_UI} ${MULTIMC_QRC})
|
||||
qt5_use_modules(multimc5 Widgets)
|
||||
link_libraries(multimc5 quazip patchlib)
|
||||
add_dependencies(multimc5 MultiMCLauncher)
|
||||
install(TARGETS multimc5 RUNTIME DESTINATION bin)
|
17
config.h.in
Normal file
17
config.h.in
Normal file
@ -0,0 +1,17 @@
|
||||
#define VERSION_MAJOR @MultiMC_VERSION_MAJOR@
|
||||
#define VERSION_MINOR @MultiMC_VERSION_MINOR@
|
||||
#define VERSION_REVISION @MultiMC_VERSION_REV@
|
||||
#define VERSION_BUILD @MultiMC_VERSION_BUILD@
|
||||
|
||||
#define VERSION_STR "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_REV@.@MultiMC_VERSION_BUILD@"
|
||||
|
||||
#define x86 1
|
||||
#define x64 2
|
||||
|
||||
#define ARCH @MultiMC_ARCH@
|
||||
|
||||
#define JENKINS_BUILD_TAG "@MultiMC_BUILD_TAG@"
|
||||
|
||||
#define JENKINS_JOB_URL "@MultiMC_JOB_URL@"
|
||||
|
||||
#define USE_HTTPS @MultiMC_USE_HTTPS@
|
83
java/annotations.cpp
Normal file
83
java/annotations.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include "classfile.h"
|
||||
#include "annotations.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace java
|
||||
{
|
||||
std::string annotation::toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl;
|
||||
ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl;
|
||||
for(unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
std::pair<uint16_t, element_value *> &val = name_val_pairs[i];
|
||||
auto name_idx = val.first;
|
||||
ss << pool[name_idx].str_data << "(" << name_idx << ")" << " = " << val.second->toString() << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
annotation * annotation::read (util::membuffer& input, constant_pool& pool)
|
||||
{
|
||||
uint16_t type_index = 0;
|
||||
input.read_be(type_index);
|
||||
annotation * ann = new annotation(type_index,pool);
|
||||
|
||||
uint16_t num_pairs = 0;
|
||||
input.read_be(num_pairs);
|
||||
while(num_pairs)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
// read name index
|
||||
input.read_be(name_idx);
|
||||
auto elem = element_value::readElementValue(input,pool);
|
||||
// read value
|
||||
ann->add_pair(name_idx, elem);
|
||||
num_pairs --;
|
||||
}
|
||||
return ann;
|
||||
}
|
||||
|
||||
element_value* element_value::readElementValue ( util::membuffer& input, java::constant_pool& pool )
|
||||
{
|
||||
element_value_type type = INVALID;
|
||||
input.read(type);
|
||||
uint16_t index = 0;
|
||||
uint16_t index2 = 0;
|
||||
std::vector <element_value *> vals;
|
||||
switch (type)
|
||||
{
|
||||
case PRIMITIVE_BYTE:
|
||||
case PRIMITIVE_CHAR:
|
||||
case PRIMITIVE_DOUBLE:
|
||||
case PRIMITIVE_FLOAT:
|
||||
case PRIMITIVE_INT:
|
||||
case PRIMITIVE_LONG:
|
||||
case PRIMITIVE_SHORT:
|
||||
case PRIMITIVE_BOOLEAN:
|
||||
case STRING:
|
||||
input.read_be(index);
|
||||
return new element_value_simple(type, index, pool);
|
||||
case ENUM_CONSTANT:
|
||||
input.read_be(index);
|
||||
input.read_be(index2);
|
||||
return new element_value_enum(type, index, index2, pool);
|
||||
case CLASS: // Class
|
||||
input.read_be(index);
|
||||
return new element_value_class(type, index, pool);
|
||||
case ANNOTATION: // Annotation
|
||||
// FIXME: runtime visibility info needs to be passed from parent
|
||||
return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool);
|
||||
case ARRAY: // Array
|
||||
input.read_be(index);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
vals.push_back(element_value::readElementValue(input, pool));
|
||||
}
|
||||
return new element_value_array(ARRAY, vals, pool);
|
||||
default:
|
||||
throw new java::classfile_exception();
|
||||
}
|
||||
}
|
||||
}
|
252
java/annotations.h
Normal file
252
java/annotations.h
Normal file
@ -0,0 +1,252 @@
|
||||
#pragma once
|
||||
#include "classfile.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace java
|
||||
{
|
||||
enum element_value_type : uint8_t
|
||||
{
|
||||
INVALID = 0,
|
||||
STRING = 's',
|
||||
ENUM_CONSTANT = 'e',
|
||||
CLASS = 'c',
|
||||
ANNOTATION = '@',
|
||||
ARRAY = '[', // one array dimension
|
||||
PRIMITIVE_INT = 'I', // integer
|
||||
PRIMITIVE_BYTE = 'B', // signed byte
|
||||
PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16
|
||||
PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value
|
||||
PRIMITIVE_FLOAT = 'F', // single-precision floating-point value
|
||||
PRIMITIVE_LONG = 'J', // long integer
|
||||
PRIMITIVE_SHORT = 'S', // signed short
|
||||
PRIMITIVE_BOOLEAN = 'Z' // true or false
|
||||
};
|
||||
/**
|
||||
* The element_value structure is a discriminated union representing the value of an element-value pair.
|
||||
* It is used to represent element values in all attributes that describe annotations
|
||||
* - RuntimeVisibleAnnotations
|
||||
* - RuntimeInvisibleAnnotations
|
||||
* - RuntimeVisibleParameterAnnotations
|
||||
* - RuntimeInvisibleParameterAnnotations).
|
||||
*
|
||||
* The element_value structure has the following format:
|
||||
*/
|
||||
class element_value
|
||||
{
|
||||
protected:
|
||||
element_value_type type;
|
||||
constant_pool & pool;
|
||||
|
||||
public:
|
||||
element_value(element_value_type type, constant_pool & pool): type(type), pool(pool) {};
|
||||
|
||||
element_value_type getElementValueType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
virtual std::string toString() = 0;
|
||||
|
||||
static element_value * readElementValue(util::membuffer & input, constant_pool & pool);
|
||||
};
|
||||
|
||||
/**
|
||||
* Each value of the annotations table represents a single runtime-visible annotation on a program element.
|
||||
* The annotation structure has the following format:
|
||||
*/
|
||||
class annotation
|
||||
{
|
||||
public:
|
||||
typedef std::vector< std::pair<uint16_t, element_value * > > value_list;
|
||||
protected:
|
||||
/**
|
||||
* The value of the type_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a field descriptor representing the annotation type corresponding
|
||||
* to the annotation represented by this annotation structure.
|
||||
*/
|
||||
uint16_t type_index;
|
||||
/**
|
||||
* map between element_name_index and value.
|
||||
*
|
||||
* The value of the element_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure representing
|
||||
* a valid field descriptor (§4.3.2) that denotes the name of the annotation type element represented
|
||||
* by this element_value_pairs entry.
|
||||
*/
|
||||
value_list name_val_pairs;
|
||||
/**
|
||||
* Reference to the parent constant pool
|
||||
*/
|
||||
constant_pool & pool;
|
||||
public:
|
||||
annotation(uint16_t type_index, constant_pool& pool):type_index(type_index), pool(pool) {};
|
||||
~annotation()
|
||||
{
|
||||
for(unsigned i = 0 ; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
delete name_val_pairs[i].second;
|
||||
}
|
||||
}
|
||||
void add_pair(uint16_t key, element_value * value)
|
||||
{
|
||||
name_val_pairs.push_back(std::make_pair(key, value));
|
||||
};
|
||||
value_list::const_iterator begin()
|
||||
{
|
||||
return name_val_pairs.cbegin();
|
||||
}
|
||||
value_list::const_iterator end()
|
||||
{
|
||||
return name_val_pairs.cend();
|
||||
}
|
||||
std::string toString();
|
||||
static annotation * read(util::membuffer & input, constant_pool & pool);
|
||||
};
|
||||
typedef std::vector<annotation *> annotation_table;
|
||||
|
||||
|
||||
/// type for simple value annotation elements
|
||||
class element_value_simple : public element_value
|
||||
{
|
||||
protected:
|
||||
/// index of the constant in the constant pool
|
||||
uint16_t index;
|
||||
public:
|
||||
element_value_simple(element_value_type type, uint16_t index , constant_pool& pool):
|
||||
element_value(type, pool), index(index)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
};
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return pool[index].toString();
|
||||
};
|
||||
};
|
||||
/// The enum_const_value item is used if the tag item is 'e'.
|
||||
class element_value_enum : public element_value
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The value of the type_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a valid field descriptor (§4.3.2) that denotes the internal form of the binary
|
||||
* name (§4.2.1) of the type of the enum constant represented by this element_value structure.
|
||||
*/
|
||||
uint16_t typeIndex;
|
||||
/**
|
||||
* The value of the const_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the simple name of the enum constant represented by this element_value structure.
|
||||
*/
|
||||
uint16_t valueIndex;
|
||||
public:
|
||||
element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex, constant_pool& pool):
|
||||
element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getValueIndex()
|
||||
{
|
||||
return valueIndex;
|
||||
}
|
||||
uint16_t getTypeIndex()
|
||||
{
|
||||
return typeIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "enum value";
|
||||
};
|
||||
};
|
||||
|
||||
class element_value_class : public element_value
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The class_info_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the return descriptor (§4.3.3) of the type that is reified by the class
|
||||
* represented by this element_value structure.
|
||||
*
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
*
|
||||
* Or in plain english, you can store type information in annotations. Yay.
|
||||
*/
|
||||
uint16_t classIndex;
|
||||
public:
|
||||
element_value_class(element_value_type type, uint16_t classIndex, constant_pool& pool):
|
||||
element_value(type, pool), classIndex(classIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return classIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "class";
|
||||
};
|
||||
};
|
||||
|
||||
/// nested annotations... yay
|
||||
class element_value_annotation : public element_value
|
||||
{
|
||||
private:
|
||||
annotation * nestedAnnotation;
|
||||
public:
|
||||
element_value_annotation(element_value_type type, annotation * nestedAnnotation, constant_pool& pool):
|
||||
element_value(type, pool), nestedAnnotation(nestedAnnotation)
|
||||
{};
|
||||
~element_value_annotation()
|
||||
{
|
||||
if(nestedAnnotation)
|
||||
{
|
||||
delete nestedAnnotation;
|
||||
nestedAnnotation = nullptr;
|
||||
}
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "nested annotation";
|
||||
};
|
||||
};
|
||||
|
||||
/// and arrays!
|
||||
class element_value_array : public element_value
|
||||
{
|
||||
public:
|
||||
typedef std::vector <element_value *> elem_vec;
|
||||
protected:
|
||||
elem_vec values;
|
||||
public:
|
||||
element_value_array ( element_value_type type, std::vector <element_value *>& values, constant_pool& pool ):
|
||||
element_value(type, pool), values(values)
|
||||
{};
|
||||
~element_value_array ()
|
||||
{
|
||||
for(unsigned i = 0; i < values.size();i++)
|
||||
{
|
||||
delete values[i];
|
||||
}
|
||||
};
|
||||
elem_vec::const_iterator begin()
|
||||
{
|
||||
return values.cbegin();
|
||||
}
|
||||
elem_vec::const_iterator end()
|
||||
{
|
||||
return values.cend();
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "array";
|
||||
};
|
||||
};
|
||||
}
|
153
java/classfile.h
Normal file
153
java/classfile.h
Normal file
@ -0,0 +1,153 @@
|
||||
#pragma once
|
||||
#include "membuffer.h"
|
||||
#include "constants.h"
|
||||
#include "annotations.h"
|
||||
#include <map>
|
||||
namespace java
|
||||
{
|
||||
/**
|
||||
* Class representing a Java .class file
|
||||
*/
|
||||
class classfile : public util::membuffer
|
||||
{
|
||||
public:
|
||||
classfile(char * data, std::size_t size) : membuffer(data, size)
|
||||
{
|
||||
valid = false;
|
||||
is_synthetic = false;
|
||||
read_be(magic);
|
||||
if(magic != 0xCAFEBABE)
|
||||
throw new classfile_exception();
|
||||
read_be(minor_version);
|
||||
read_be(major_version);
|
||||
constants.load(*this);
|
||||
read_be(access_flags);
|
||||
read_be(this_class);
|
||||
read_be(super_class);
|
||||
|
||||
// Interfaces
|
||||
uint16_t iface_count = 0;
|
||||
read_be(iface_count);
|
||||
while (iface_count)
|
||||
{
|
||||
uint16_t iface;
|
||||
read_be(iface);
|
||||
interfaces.push_back(iface);
|
||||
iface_count --;
|
||||
}
|
||||
|
||||
// Fields
|
||||
// read fields (and attributes from inside fields) (and possible inner classes. yay for recursion!)
|
||||
// for now though, we will ignore all attributes
|
||||
/*
|
||||
* field_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t field_count = 0;
|
||||
read_be(field_count);
|
||||
while (field_count)
|
||||
{
|
||||
// skip field stuff
|
||||
skip(6);
|
||||
// and skip field attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while(attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count --;
|
||||
}
|
||||
field_count --;
|
||||
}
|
||||
|
||||
// class methods
|
||||
/*
|
||||
* method_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t method_count = 0;
|
||||
read_be(method_count);
|
||||
while( method_count )
|
||||
{
|
||||
skip(6);
|
||||
// and skip method attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while(attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count --;
|
||||
}
|
||||
method_count --;
|
||||
}
|
||||
|
||||
// class attributes
|
||||
// there are many kinds of attributes. this is just the generic wrapper structure.
|
||||
// type is decided by attribute name. extensions to the standard are *possible*
|
||||
// class annotations are one kind of a attribute (one per class)
|
||||
/*
|
||||
* attribute_info
|
||||
* {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u1 info[attribute_length];
|
||||
* }
|
||||
*/
|
||||
uint16_t class_attr_count = 0;
|
||||
read_be(class_attr_count);
|
||||
while(class_attr_count)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
read_be(name_idx);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
|
||||
auto name = constants[name_idx];
|
||||
if(name.str_data == "RuntimeVisibleAnnotations")
|
||||
{
|
||||
uint16_t num_annotations = 0;
|
||||
read_be(num_annotations);
|
||||
while (num_annotations)
|
||||
{
|
||||
visible_class_annotations.push_back(annotation::read(*this, constants));
|
||||
num_annotations --;
|
||||
}
|
||||
}
|
||||
else skip(attr_length);
|
||||
class_attr_count --;
|
||||
}
|
||||
valid = true;
|
||||
};
|
||||
bool valid;
|
||||
bool is_synthetic;
|
||||
uint32_t magic;
|
||||
uint16_t minor_version;
|
||||
uint16_t major_version;
|
||||
constant_pool constants;
|
||||
uint16_t access_flags;
|
||||
uint16_t this_class;
|
||||
uint16_t super_class;
|
||||
// interfaces this class implements ? must be. investigate.
|
||||
std::vector<uint16_t> interfaces;
|
||||
// FIXME: doesn't free up memory on delete
|
||||
java::annotation_table visible_class_annotations;
|
||||
};
|
||||
}
|
208
java/constants.h
Normal file
208
java/constants.h
Normal file
@ -0,0 +1,208 @@
|
||||
#pragma once
|
||||
#include "errors.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace java
|
||||
{
|
||||
class constant
|
||||
{
|
||||
public:
|
||||
enum type_t:uint8_t
|
||||
{
|
||||
j_hole = 0, // HACK: this is a hole in the array, because java is crazy
|
||||
j_string_data = 1,
|
||||
j_int = 3,
|
||||
j_float = 4,
|
||||
j_long = 5,
|
||||
j_double = 6,
|
||||
j_class = 7,
|
||||
j_string = 8,
|
||||
j_fieldref = 9,
|
||||
j_methodref = 10,
|
||||
j_interface_methodref = 11,
|
||||
j_nameandtype = 12
|
||||
} type;
|
||||
constant(util::membuffer & buf )
|
||||
{
|
||||
buf.read(type);
|
||||
// invalid constant type!
|
||||
if(type > j_nameandtype || type == (type_t)0 || type == (type_t)2)
|
||||
throw new classfile_exception();
|
||||
|
||||
// load data depending on type
|
||||
switch(type)
|
||||
{
|
||||
case j_float:
|
||||
case j_int:
|
||||
buf.read_be(int_data); // same as float data really
|
||||
break;
|
||||
case j_double:
|
||||
case j_long:
|
||||
buf.read_be(long_data); // same as double
|
||||
break;
|
||||
case j_class:
|
||||
buf.read_be(ref_type.class_idx);
|
||||
break;
|
||||
case j_fieldref:
|
||||
case j_methodref:
|
||||
case j_interface_methodref:
|
||||
buf.read_be(ref_type.class_idx);
|
||||
buf.read_be(ref_type.name_and_type_idx);
|
||||
break;
|
||||
case j_string:
|
||||
buf.read_be(index);
|
||||
break;
|
||||
case j_string_data:
|
||||
// HACK HACK: for now, we call these UTF-8 and do no further processing.
|
||||
// Later, we should do some decoding. It's really modified UTF-8
|
||||
// * U+0000 is represented as 0xC0,0x80 invalid character
|
||||
// * any single zero byte ends the string
|
||||
// * characters above U+10000 are encoded like in CESU-8
|
||||
buf.read_jstr(str_data);
|
||||
break;
|
||||
case j_nameandtype:
|
||||
buf.read_be(name_and_type.name_index);
|
||||
buf.read_be(name_and_type.descriptor_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
constant(int fake)
|
||||
{
|
||||
type = j_hole;
|
||||
}
|
||||
std::string toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
switch(type)
|
||||
{
|
||||
case j_hole:
|
||||
ss << "Fake legacy entry";
|
||||
break;
|
||||
case j_float:
|
||||
ss << "Float: " << float_data;
|
||||
break;
|
||||
case j_double:
|
||||
ss << "Double: " << double_data;
|
||||
break;
|
||||
case j_int:
|
||||
ss << "Int: " << int_data;
|
||||
break;
|
||||
case j_long:
|
||||
ss << "Long: " << long_data;
|
||||
break;
|
||||
case j_string_data:
|
||||
ss << "StrData: " << str_data;
|
||||
break;
|
||||
case j_string:
|
||||
ss << "Str: " << index;
|
||||
break;
|
||||
case j_fieldref:
|
||||
ss << "FieldRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
|
||||
break;
|
||||
case j_methodref:
|
||||
ss << "MethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
|
||||
break;
|
||||
case j_interface_methodref:
|
||||
ss << "IfMethodRef: " << ref_type.class_idx << " " << ref_type.name_and_type_idx;
|
||||
break;
|
||||
case j_class:
|
||||
ss << "Class: " << ref_type.class_idx;
|
||||
break;
|
||||
case j_nameandtype:
|
||||
ss << "NameAndType: " << name_and_type.name_index << " " << name_and_type.descriptor_index;
|
||||
break;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string str_data; /** String data in 'modified utf-8'.*/
|
||||
// store everything here.
|
||||
union
|
||||
{
|
||||
int32_t int_data;
|
||||
int64_t long_data;
|
||||
float float_data;
|
||||
double double_data;
|
||||
uint16_t index;
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* Class reference:
|
||||
* an index within the constant pool to a UTF-8 string containing
|
||||
* the fully qualified class name (in internal format)
|
||||
* Used for j_class, j_fieldref, j_methodref and j_interface_methodref
|
||||
*/
|
||||
uint16_t class_idx;
|
||||
// used for j_fieldref, j_methodref and j_interface_methodref
|
||||
uint16_t name_and_type_idx;
|
||||
} ref_type;
|
||||
struct
|
||||
{
|
||||
uint16_t name_index;
|
||||
uint16_t descriptor_index;
|
||||
} name_and_type;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* A helper class that represents the custom container used in Java class file for storage of constants
|
||||
*/
|
||||
class constant_pool
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a pool of constants
|
||||
*/
|
||||
constant_pool(){}
|
||||
/**
|
||||
* Load a java constant pool
|
||||
*/
|
||||
void load(util::membuffer & buf)
|
||||
{
|
||||
uint16_t length = 0;
|
||||
buf.read_be(length);
|
||||
length --;
|
||||
uint16_t index = 1;
|
||||
const constant * last_constant = nullptr;
|
||||
while(length)
|
||||
{
|
||||
const constant & cnst = constant(buf);
|
||||
constants.push_back(cnst);
|
||||
last_constant = &constants[constants.size() - 1];
|
||||
if(last_constant->type == constant::j_double || last_constant->type == constant::j_long)
|
||||
{
|
||||
// push in a fake constant to preserve indexing
|
||||
constants.push_back(constant(0));
|
||||
length-=2;
|
||||
index+=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
length--;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
};
|
||||
typedef std::vector<java::constant> container_type;
|
||||
/**
|
||||
* Access constants based on jar file index numbers (index of the first element is 1)
|
||||
*/
|
||||
java::constant & operator[](std::size_t constant_index)
|
||||
{
|
||||
if(constant_index == 0 || constant_index > constants.size())
|
||||
{
|
||||
throw new classfile_exception();
|
||||
}
|
||||
return constants[constant_index - 1];
|
||||
};
|
||||
container_type::const_iterator begin() const
|
||||
{
|
||||
return constants.begin();
|
||||
};
|
||||
container_type::const_iterator end() const
|
||||
{
|
||||
return constants.end();
|
||||
}
|
||||
private:
|
||||
container_type constants;
|
||||
};
|
||||
}
|
62
java/endian.h
Normal file
62
java/endian.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Swap bytes between big endian and local number representation
|
||||
*/
|
||||
namespace util
|
||||
{
|
||||
#ifdef MULTIMC_BIG_ENDIAN
|
||||
inline uint64_t bigswap(uint64_t x)
|
||||
{
|
||||
return x;
|
||||
};
|
||||
inline uint32_t bigswap(uint32_t x)
|
||||
{
|
||||
return x;
|
||||
};
|
||||
inline uint16_t bigswap(uint16_t x)
|
||||
{
|
||||
return x;
|
||||
};
|
||||
inline int64_t bigswap(int64_t x)
|
||||
{
|
||||
return x;
|
||||
};
|
||||
inline int32_t bigswap(int32_t x)
|
||||
{
|
||||
return x;
|
||||
};
|
||||
inline int16_t bigswap(int16_t x)
|
||||
{
|
||||
return x;
|
||||
};
|
||||
#else
|
||||
inline uint64_t bigswap(uint64_t x)
|
||||
{
|
||||
return (x>>56) | ((x<<40) & 0x00FF000000000000) | ((x<<24) & 0x0000FF0000000000) | ((x<<8) & 0x000000FF00000000) |
|
||||
((x>>8) & 0x00000000FF000000) | ((x>>24) & 0x0000000000FF0000) | ((x>>40) & 0x000000000000FF00) | (x<<56);
|
||||
};
|
||||
inline uint32_t bigswap(uint32_t x)
|
||||
{
|
||||
return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
|
||||
};
|
||||
inline uint16_t bigswap(uint16_t x)
|
||||
{
|
||||
return (x>>8) | (x<<8);
|
||||
};
|
||||
inline int64_t bigswap(int64_t x)
|
||||
{
|
||||
return (x>>56) | ((x<<40) & 0x00FF000000000000) | ((x<<24) & 0x0000FF0000000000) | ((x<<8) & 0x000000FF00000000) |
|
||||
((x>>8) & 0x00000000FF000000) | ((x>>24) & 0x0000000000FF0000) | ((x>>40) & 0x000000000000FF00) | (x<<56);
|
||||
};
|
||||
inline int32_t bigswap(int32_t x)
|
||||
{
|
||||
return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
|
||||
};
|
||||
inline int16_t bigswap(int16_t x)
|
||||
{
|
||||
return (x>>8) | (x<<8);
|
||||
};
|
||||
#endif
|
||||
}
|
6
java/errors.h
Normal file
6
java/errors.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <exception>
|
||||
namespace java
|
||||
{
|
||||
class classfile_exception : public std::exception {};
|
||||
}
|
69
java/javautils.cpp
Normal file
69
java/javautils.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "multimc_pragma.h"
|
||||
#include "classfile.h"
|
||||
#include "javautils.h"
|
||||
//#include <wx/zipstrm.h>
|
||||
#include <memory>
|
||||
//#include <wx/wfstream.h>
|
||||
//#include "mcversionlist.h"
|
||||
|
||||
namespace javautils
|
||||
{
|
||||
QString GetMinecraftJarVersion(QString jar)
|
||||
{
|
||||
return "Unknown";
|
||||
/*
|
||||
wxString fullpath = jar.GetFullPath();
|
||||
wxString version = MCVer_Unknown;
|
||||
if(!jar.FileExists())
|
||||
return version;
|
||||
std::auto_ptr<wxZipEntry> entry;
|
||||
// convert the local name we are looking for into the internal format
|
||||
wxString name = wxZipEntry::GetInternalName("net/minecraft/client/Minecraft.class",wxPATH_UNIX);
|
||||
|
||||
// open the zip
|
||||
wxFFileInputStream inStream(jar.GetFullPath());
|
||||
wxZipInputStream zipIn(inStream);
|
||||
|
||||
// call GetNextEntry() until the required internal name is found
|
||||
do
|
||||
{
|
||||
entry.reset(zipIn.GetNextEntry());
|
||||
}
|
||||
while (entry.get() != NULL && entry->GetInternalName() != name);
|
||||
auto myentry = entry.get();
|
||||
if (myentry == NULL)
|
||||
return version;
|
||||
|
||||
// we got the entry, read the data
|
||||
std::size_t size = myentry->GetSize();
|
||||
char *classdata = new char[size];
|
||||
zipIn.Read(classdata,size);
|
||||
try
|
||||
{
|
||||
char * temp = classdata;
|
||||
java::classfile Minecraft_jar(temp,size);
|
||||
auto cnst = Minecraft_jar.constants;
|
||||
auto iter = cnst.begin();
|
||||
while (iter != cnst.end())
|
||||
{
|
||||
const java::constant & constant = *iter;
|
||||
if(constant.type != java::constant::j_string_data)
|
||||
{
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
auto & str = constant.str_data;
|
||||
const char * lookfor = "Minecraft Minecraft "; // length = 20
|
||||
if(str.compare(0,20,lookfor) == 0)
|
||||
{
|
||||
version = str.substr(20).data();
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
} catch(java::classfile_exception &){}
|
||||
delete[] classdata;
|
||||
return version;
|
||||
*/
|
||||
}
|
||||
}
|
9
java/javautils.h
Normal file
9
java/javautils.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
namespace javautils
|
||||
{
|
||||
/*
|
||||
* Get the version from a minecraft.jar by parsing its class files. Expensive!
|
||||
*/
|
||||
QString GetMinecraftJarVersion(QString jar);
|
||||
}
|
64
java/membuffer.h
Normal file
64
java/membuffer.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
#include "endian.h"
|
||||
|
||||
namespace util
|
||||
{
|
||||
class membuffer
|
||||
{
|
||||
public:
|
||||
membuffer(char * buffer, std::size_t size)
|
||||
{
|
||||
current = start = buffer;
|
||||
end = start + size;
|
||||
}
|
||||
~membuffer()
|
||||
{
|
||||
// maybe? possibly? left out to avoid confusion. for now.
|
||||
//delete start;
|
||||
}
|
||||
/**
|
||||
* Read some value. That's all ;)
|
||||
*/
|
||||
template <class T>
|
||||
void read(T& val)
|
||||
{
|
||||
val = *(T *)current;
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a big-endian number
|
||||
* valid for 2-byte, 4-byte and 8-byte variables
|
||||
*/
|
||||
template <class T>
|
||||
void read_be(T& val)
|
||||
{
|
||||
val = util::bigswap(*(T *)current);
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a string in the format:
|
||||
* 2B length (big endian, unsigned)
|
||||
* length bytes data
|
||||
*/
|
||||
void read_jstr(std::string & str)
|
||||
{
|
||||
uint16_t length = 0;
|
||||
read_be(length);
|
||||
str.append(current,length);
|
||||
current += length;
|
||||
}
|
||||
/**
|
||||
* Skip N bytes
|
||||
*/
|
||||
void skip (std::size_t N)
|
||||
{
|
||||
current += N;
|
||||
}
|
||||
private:
|
||||
char * start, *end, *current;
|
||||
};
|
||||
}
|
35
java/test.cpp
Normal file
35
java/test.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
#include "classfile.h"
|
||||
#include "annotations.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc > 1)
|
||||
{
|
||||
std::ifstream file_in(argv[1]);
|
||||
if(file_in.is_open())
|
||||
{
|
||||
file_in.seekg(0, std::_S_end);
|
||||
auto length = file_in.tellg();
|
||||
char * data = new char[length];
|
||||
file_in.seekg(0);
|
||||
file_in.read(data,length);
|
||||
java::classfile cf (data, length);
|
||||
java::annotation_table atable = cf.visible_class_annotations;
|
||||
for(int i = 0; i < atable.size(); i++)
|
||||
{
|
||||
std::cout << atable[i]->toString() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to open file : " << argv[1] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::cerr << "No file to open :(" << std::endl;
|
||||
return 1;
|
||||
}
|
23
launcher/CMakeLists.txt
Normal file
23
launcher/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 2.8.6)
|
||||
project(launcher Java)
|
||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}")
|
||||
find_package(Java 1.6 REQUIRED COMPONENTS Development)
|
||||
|
||||
|
||||
include(UseJava)
|
||||
set(CMAKE_JAVA_JAR_ENTRY_POINT MultiMCLauncher)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked)
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/../resources")
|
||||
|
||||
set(SRC
|
||||
MultiMCLauncher.java
|
||||
org/simplericity/macify/eawt/Application.java
|
||||
org/simplericity/macify/eawt/ApplicationAdapter.java
|
||||
org/simplericity/macify/eawt/ApplicationEvent.java
|
||||
org/simplericity/macify/eawt/ApplicationListener.java
|
||||
org/simplericity/macify/eawt/DefaultApplication.java
|
||||
net/minecraft/Launcher.java
|
||||
MCFrame.java
|
||||
)
|
||||
|
||||
add_jar(MultiMCLauncher ${SRC})
|
123
launcher/MCFrame.java
Normal file
123
launcher/MCFrame.java
Normal file
@ -0,0 +1,123 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import net.minecraft.Launcher;
|
||||
import java.applet.Applet;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class MCFrame extends Frame implements WindowListener
|
||||
{
|
||||
private Launcher appletWrap = null;
|
||||
public MCFrame(String title)
|
||||
{
|
||||
super(title);
|
||||
BufferedImage image = null;
|
||||
try
|
||||
{
|
||||
image = ImageIO.read(new File("icon.png"));
|
||||
setIconImage(image);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.addWindowListener(this);
|
||||
}
|
||||
|
||||
public void start(Applet mcApplet, String user, String session, Dimension winSize, boolean maximize)
|
||||
{
|
||||
try
|
||||
{
|
||||
appletWrap = new Launcher(mcApplet, new URL("http://www.minecraft.net/game"));
|
||||
}
|
||||
catch (MalformedURLException ignored){}
|
||||
|
||||
appletWrap.setParameter("username", user);
|
||||
appletWrap.setParameter("sessionid", session);
|
||||
appletWrap.setParameter("stand-alone", "true"); // Show the quit button.
|
||||
mcApplet.setStub(appletWrap);
|
||||
|
||||
this.add(appletWrap);
|
||||
appletWrap.setPreferredSize(winSize);
|
||||
this.pack();
|
||||
this.setLocationRelativeTo(null);
|
||||
this.setResizable(true);
|
||||
if (maximize)
|
||||
this.setExtendedState(MAXIMIZED_BOTH);
|
||||
|
||||
validate();
|
||||
appletWrap.init();
|
||||
appletWrap.start();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowActivated(WindowEvent e) {}
|
||||
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {}
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
new Thread()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(30000L);
|
||||
} catch (InterruptedException localInterruptedException)
|
||||
{
|
||||
localInterruptedException.printStackTrace();
|
||||
}
|
||||
System.out.println("FORCING EXIT!");
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
.start();
|
||||
|
||||
if (appletWrap != null)
|
||||
{
|
||||
appletWrap.stop();
|
||||
appletWrap.destroy();
|
||||
}
|
||||
// old minecraft versions can hang without this >_<
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent e) {}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {}
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) {}
|
||||
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {}
|
||||
}
|
331
launcher/MultiMCLauncher.java
Normal file
331
launcher/MultiMCLauncher.java
Normal file
@ -0,0 +1,331 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import org.simplericity.macify.eawt.Application;
|
||||
import org.simplericity.macify.eawt.DefaultApplication;
|
||||
|
||||
public class MultiMCLauncher
|
||||
{
|
||||
/**
|
||||
* @param args
|
||||
* The arguments you want to launch Minecraft with. New path,
|
||||
* Username, Session ID.
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
{
|
||||
if (args.length < 3)
|
||||
{
|
||||
System.out.println("Not enough arguments.");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// Set the OSX application icon first, if we are on OSX.
|
||||
Application application = new DefaultApplication();
|
||||
if(application.isMac())
|
||||
{
|
||||
try
|
||||
{
|
||||
BufferedImage image = ImageIO.read(new File("icon.png"));
|
||||
application.setApplicationIconImage(image);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String userName = args[0];
|
||||
String sessionId = args[1];
|
||||
String windowtitle = args[2];
|
||||
String windowParams = args[3];
|
||||
String lwjgl = args[4];
|
||||
String cwd = System.getProperty("user.dir");
|
||||
|
||||
Dimension winSize = new Dimension(854, 480);
|
||||
boolean maximize = false;
|
||||
boolean compatMode = false;
|
||||
|
||||
|
||||
String[] dimStrings = windowParams.split("x");
|
||||
|
||||
if (windowParams.equalsIgnoreCase("compatmode"))
|
||||
{
|
||||
compatMode = true;
|
||||
}
|
||||
else if (windowParams.equalsIgnoreCase("max"))
|
||||
{
|
||||
maximize = true;
|
||||
}
|
||||
else if (dimStrings.length == 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
winSize = new Dimension(Integer.parseInt(dimStrings[0]),
|
||||
Integer.parseInt(dimStrings[1]));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
System.out.println("Invalid Window size argument, " +
|
||||
"using default.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Invalid Window size argument, " +
|
||||
"using default.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File binDir = new File(cwd, "bin");
|
||||
File lwjglDir;
|
||||
if(lwjgl.equalsIgnoreCase("Mojang"))
|
||||
lwjglDir = binDir;
|
||||
else
|
||||
lwjglDir = new File(lwjgl);
|
||||
|
||||
System.out.println("Loading jars...");
|
||||
String[] lwjglJars = new String[] {
|
||||
"lwjgl.jar", "lwjgl_util.jar", "jinput.jar"
|
||||
};
|
||||
|
||||
URL[] urls = new URL[4];
|
||||
try
|
||||
{
|
||||
File f = new File(binDir, "minecraft.jar");
|
||||
urls[0] = f.toURI().toURL();
|
||||
System.out.println("Loading URL: " + urls[0].toString());
|
||||
|
||||
for (int i = 1; i < urls.length; i++)
|
||||
{
|
||||
File jar = new File(lwjglDir, lwjglJars[i-1]);
|
||||
urls[i] = jar.toURI().toURL();
|
||||
System.out.println("Loading URL: " + urls[i].toString());
|
||||
}
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
System.err.println("MalformedURLException, " + e.toString());
|
||||
System.exit(5);
|
||||
}
|
||||
|
||||
System.out.println("Loading natives...");
|
||||
String nativesDir = new File(lwjglDir, "natives").toString();
|
||||
|
||||
System.setProperty("org.lwjgl.librarypath", nativesDir);
|
||||
System.setProperty("net.java.games.input.librarypath", nativesDir);
|
||||
|
||||
URLClassLoader cl =
|
||||
new URLClassLoader(urls, MultiMCLauncher.class.getClassLoader());
|
||||
|
||||
// Get the Minecraft Class.
|
||||
Class<?> mc = null;
|
||||
try
|
||||
{
|
||||
mc = cl.loadClass("net.minecraft.client.Minecraft");
|
||||
|
||||
Field f = getMCPathField(mc);
|
||||
|
||||
if (f == null)
|
||||
{
|
||||
System.err.println("Could not find Minecraft path field. Launch failed.");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
f.setAccessible(true);
|
||||
f.set(null, new File(cwd));
|
||||
// And set it.
|
||||
System.out.println("Fixed Minecraft Path: Field was " + f.toString());
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
System.err.println("Can't find main class. Searching...");
|
||||
|
||||
// Look for any class that looks like the main class.
|
||||
File mcJar = new File(new File(cwd, "bin"), "minecraft.jar");
|
||||
ZipFile zip = null;
|
||||
try
|
||||
{
|
||||
zip = new ZipFile(mcJar);
|
||||
} catch (ZipException e1)
|
||||
{
|
||||
e1.printStackTrace();
|
||||
System.err.println("Search failed.");
|
||||
System.exit(-1);
|
||||
} catch (IOException e1)
|
||||
{
|
||||
e1.printStackTrace();
|
||||
System.err.println("Search failed.");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
ArrayList<String> classes = new ArrayList<String>();
|
||||
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
ZipEntry entry = entries.nextElement();
|
||||
if (entry.getName().endsWith(".class"))
|
||||
{
|
||||
String entryName = entry.getName().substring(0, entry.getName().lastIndexOf('.'));
|
||||
entryName = entryName.replace('/', '.');
|
||||
System.out.println("Found class: " + entryName);
|
||||
classes.add(entryName);
|
||||
}
|
||||
}
|
||||
|
||||
for (String clsName : classes)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> cls = cl.loadClass(clsName);
|
||||
if (!Runnable.class.isAssignableFrom(cls))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Found class implementing runnable: " +
|
||||
cls.getName());
|
||||
}
|
||||
|
||||
if (getMCPathField(cls) == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Found class implementing runnable " +
|
||||
"with mcpath field: " + cls.getName());
|
||||
}
|
||||
|
||||
mc = cls;
|
||||
break;
|
||||
}
|
||||
catch (ClassNotFoundException e1)
|
||||
{
|
||||
// Ignore
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (mc == null)
|
||||
{
|
||||
System.err.println("Failed to find Minecraft main class.");
|
||||
System.exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Found main class: " + mc.getName());
|
||||
}
|
||||
}
|
||||
|
||||
System.setProperty("minecraft.applet.TargetDirectory", cwd);
|
||||
|
||||
String[] mcArgs = new String[2];
|
||||
mcArgs[0] = userName;
|
||||
mcArgs[1] = sessionId;
|
||||
|
||||
if (compatMode)
|
||||
{
|
||||
System.out.println("Launching in compatibility mode...");
|
||||
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Launching with applet wrapper...");
|
||||
try
|
||||
{
|
||||
Class<?> MCAppletClass = cl.loadClass(
|
||||
"net.minecraft.client.MinecraftApplet");
|
||||
Applet mcappl = (Applet) MCAppletClass.newInstance();
|
||||
MCFrame mcWindow = new MCFrame(windowtitle);
|
||||
mcWindow.start(mcappl, userName, sessionId, winSize, maximize);
|
||||
} catch (InstantiationException e)
|
||||
{
|
||||
System.out.println("Applet wrapper failed! Falling back " +
|
||||
"to compatibility mode.");
|
||||
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} catch (IllegalArgumentException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.exit(2);
|
||||
} catch (IllegalAccessException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.exit(2);
|
||||
} catch (InvocationTargetException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
} catch (NoSuchMethodException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.exit(3);
|
||||
} catch (SecurityException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
System.exit(4);
|
||||
}
|
||||
}
|
||||
|
||||
public static Field getMCPathField(Class<?> mc)
|
||||
{
|
||||
Field[] fields = mc.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++)
|
||||
{
|
||||
Field f = fields[i];
|
||||
if (f.getType() != File.class)
|
||||
{
|
||||
// Has to be File
|
||||
continue;
|
||||
}
|
||||
if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC))
|
||||
{
|
||||
// And Private Static.
|
||||
continue;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
881
launcher/UseJava.cmake
Normal file
881
launcher/UseJava.cmake
Normal file
@ -0,0 +1,881 @@
|
||||
# - Use Module for Java
|
||||
# This file provides functions for Java. It is assumed that FindJava.cmake
|
||||
# has already been loaded. See FindJava.cmake for information on how to
|
||||
# load Java into your CMake project.
|
||||
#
|
||||
# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN)
|
||||
#
|
||||
# This command creates a <TARGET_NAME>.jar. It compiles the given source
|
||||
# files (SRC) and adds the given resource files (RCS) to the jar file.
|
||||
# If only resource files are given then just a jar file is created.
|
||||
#
|
||||
# Additional instructions:
|
||||
# To add compile flags to the target you can set these flags with
|
||||
# the following variable:
|
||||
#
|
||||
# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
|
||||
#
|
||||
# To add a path or a jar file to the class path you can do this
|
||||
# with the CMAKE_JAVA_INCLUDE_PATH variable.
|
||||
#
|
||||
# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
|
||||
#
|
||||
# To use a different output name for the target you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar)
|
||||
# add_jar(foobar foobar.java)
|
||||
#
|
||||
# To use a different output directory than CMAKE_CURRENT_BINARY_DIR
|
||||
# you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
|
||||
#
|
||||
# To define an entry point in your jar you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main)
|
||||
#
|
||||
# To add a VERSION to the target output name you can set it using
|
||||
# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name
|
||||
# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar
|
||||
# pointing to the jar with the version information.
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
|
||||
# add_jar(shibboleet shibbotleet.java)
|
||||
#
|
||||
# If the target is a JNI library, utilize the following commands to
|
||||
# create a JNI symbolic link:
|
||||
#
|
||||
# set(CMAKE_JNI_TARGET TRUE)
|
||||
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
|
||||
# add_jar(shibboleet shibbotleet.java)
|
||||
# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
|
||||
# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
|
||||
#
|
||||
# If a single target needs to produce more than one jar from its
|
||||
# java source code, to prevent the accumulation of duplicate class
|
||||
# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior
|
||||
# to calling the add_jar() function:
|
||||
#
|
||||
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
|
||||
# add_jar(foo foo.java)
|
||||
#
|
||||
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
|
||||
# add_jar(bar bar.java)
|
||||
#
|
||||
# Target Properties:
|
||||
# The add_jar() functions sets some target properties. You can get these
|
||||
# properties with the
|
||||
# get_property(TARGET <target_name> PROPERTY <propery_name>)
|
||||
# command.
|
||||
#
|
||||
# INSTALL_FILES The files which should be installed. This is used by
|
||||
# install_jar().
|
||||
# JNI_SYMLINK The JNI symlink which should be installed.
|
||||
# This is used by install_jni_symlink().
|
||||
# JAR_FILE The location of the jar file so that you can include
|
||||
# it.
|
||||
# CLASS_DIR The directory where the class files can be found. For
|
||||
# example to use them with javah.
|
||||
#
|
||||
# find_jar(<VAR>
|
||||
# name | NAMES name1 [name2 ...]
|
||||
# [PATHS path1 [path2 ... ENV var]]
|
||||
# [VERSIONS version1 [version2]]
|
||||
# [DOC "cache documentation string"]
|
||||
# )
|
||||
#
|
||||
# This command is used to find a full path to the named jar. A cache
|
||||
# entry named by <VAR> is created to stor the result of this command. If
|
||||
# the full path to a jar is found the result is stored in the variable
|
||||
# and the search will not repeated unless the variable is cleared. If
|
||||
# nothing is found, the result will be <VAR>-NOTFOUND, and the search
|
||||
# will be attempted again next time find_jar is invoked with the same
|
||||
# variable.
|
||||
# The name of the full path to a file that is searched for is specified
|
||||
# by the names listed after NAMES argument. Additional search locations
|
||||
# can be specified after the PATHS argument. If you require special a
|
||||
# version of a jar file you can specify it with the VERSIONS argument.
|
||||
# The argument after DOC will be used for the documentation string in
|
||||
# the cache.
|
||||
#
|
||||
# install_jar(TARGET_NAME DESTINATION)
|
||||
#
|
||||
# This command installs the TARGET_NAME files to the given DESTINATION.
|
||||
# It should be called in the same scope as add_jar() or it will fail.
|
||||
#
|
||||
# install_jni_symlink(TARGET_NAME DESTINATION)
|
||||
#
|
||||
# This command installs the TARGET_NAME JNI symlinks to the given
|
||||
# DESTINATION. It should be called in the same scope as add_jar()
|
||||
# or it will fail.
|
||||
#
|
||||
# create_javadoc(<VAR>
|
||||
# PACKAGES pkg1 [pkg2 ...]
|
||||
# [SOURCEPATH <sourcepath>]
|
||||
# [CLASSPATH <classpath>]
|
||||
# [INSTALLPATH <install path>]
|
||||
# [DOCTITLE "the documentation title"]
|
||||
# [WINDOWTITLE "the title of the document"]
|
||||
# [AUTHOR TRUE|FALSE]
|
||||
# [USE TRUE|FALSE]
|
||||
# [VERSION TRUE|FALSE]
|
||||
# )
|
||||
#
|
||||
# Create java documentation based on files or packages. For more
|
||||
# details please read the javadoc manpage.
|
||||
#
|
||||
# There are two main signatures for create_javadoc. The first
|
||||
# signature works with package names on a path with source files:
|
||||
#
|
||||
# Example:
|
||||
# create_javadoc(my_example_doc
|
||||
# PACKAGES com.exmaple.foo com.example.bar
|
||||
# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
|
||||
# WINDOWTITLE "My example"
|
||||
# DOCTITLE "<h1>My example</h1>"
|
||||
# AUTHOR TRUE
|
||||
# USE TRUE
|
||||
# VERSION TRUE
|
||||
# )
|
||||
#
|
||||
# The second signature for create_javadoc works on a given list of
|
||||
# files.
|
||||
#
|
||||
# create_javadoc(<VAR>
|
||||
# FILES file1 [file2 ...]
|
||||
# [CLASSPATH <classpath>]
|
||||
# [INSTALLPATH <install path>]
|
||||
# [DOCTITLE "the documentation title"]
|
||||
# [WINDOWTITLE "the title of the document"]
|
||||
# [AUTHOR TRUE|FALSE]
|
||||
# [USE TRUE|FALSE]
|
||||
# [VERSION TRUE|FALSE]
|
||||
# )
|
||||
#
|
||||
# Example:
|
||||
# create_javadoc(my_example_doc
|
||||
# FILES ${example_SRCS}
|
||||
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
|
||||
# WINDOWTITLE "My example"
|
||||
# DOCTITLE "<h1>My example</h1>"
|
||||
# AUTHOR TRUE
|
||||
# USE TRUE
|
||||
# VERSION TRUE
|
||||
# )
|
||||
#
|
||||
# Both signatures share most of the options. These options are the
|
||||
# same as what you can find in the javadoc manpage. Please look at
|
||||
# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and
|
||||
# VERSION.
|
||||
#
|
||||
# The documentation will be by default installed to
|
||||
#
|
||||
# ${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
|
||||
#
|
||||
# if you don't set the INSTALLPATH.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
# Copyright 2010 Ben Boeckel <ben.boeckel@kitware.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function (__java_copy_file src dest comment)
|
||||
add_custom_command(
|
||||
OUTPUT ${dest}
|
||||
COMMAND cmake -E copy_if_different
|
||||
ARGS ${src}
|
||||
${dest}
|
||||
DEPENDS ${src}
|
||||
COMMENT ${comment})
|
||||
endfunction (__java_copy_file src dest comment)
|
||||
|
||||
# define helper scripts
|
||||
set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
|
||||
set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
|
||||
|
||||
function(add_jar _TARGET_NAME)
|
||||
set(_JAVA_SOURCE_FILES ${ARGN})
|
||||
|
||||
if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
|
||||
|
||||
if (CMAKE_JAVA_JAR_ENTRY_POINT)
|
||||
set(_ENTRY_POINT_OPTION e)
|
||||
set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT})
|
||||
endif (CMAKE_JAVA_JAR_ENTRY_POINT)
|
||||
|
||||
if (LIBRARY_OUTPUT_PATH)
|
||||
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
|
||||
else (LIBRARY_OUTPUT_PATH)
|
||||
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR})
|
||||
endif (LIBRARY_OUTPUT_PATH)
|
||||
|
||||
set(CMAKE_JAVA_INCLUDE_PATH
|
||||
${CMAKE_JAVA_INCLUDE_PATH}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_JAVA_OBJECT_OUTPUT_PATH}
|
||||
${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";")
|
||||
else ()
|
||||
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":")
|
||||
endif()
|
||||
|
||||
foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH})
|
||||
set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}")
|
||||
endforeach(JAVA_INCLUDE_DIR)
|
||||
|
||||
set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
|
||||
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar")
|
||||
if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
|
||||
set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
|
||||
elseif (CMAKE_JAVA_TARGET_VERSION)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
|
||||
set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar")
|
||||
elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
|
||||
endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
|
||||
# reset
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_NAME)
|
||||
|
||||
set(_JAVA_CLASS_FILES)
|
||||
set(_JAVA_COMPILE_FILES)
|
||||
set(_JAVA_DEPENDS)
|
||||
set(_JAVA_RESOURCE_FILES)
|
||||
foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES})
|
||||
get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT)
|
||||
get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE)
|
||||
get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
|
||||
get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
|
||||
|
||||
file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL})
|
||||
file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
|
||||
string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
|
||||
string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN)
|
||||
if (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH})
|
||||
else (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH})
|
||||
endif (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH)
|
||||
|
||||
if (_JAVA_EXT MATCHES ".java")
|
||||
list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE})
|
||||
set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class")
|
||||
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE})
|
||||
|
||||
elseif (_JAVA_EXT MATCHES ".jar"
|
||||
OR _JAVA_EXT MATCHES ".war"
|
||||
OR _JAVA_EXT MATCHES ".ear"
|
||||
OR _JAVA_EXT MATCHES ".sar")
|
||||
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE})
|
||||
|
||||
elseif (_JAVA_EXT STREQUAL "")
|
||||
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
|
||||
list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
|
||||
|
||||
else (_JAVA_EXT MATCHES ".java")
|
||||
__java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE}
|
||||
${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE}
|
||||
"Copying ${_JAVA_SOURCE_FILE} to the build directory")
|
||||
list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE})
|
||||
endif (_JAVA_EXT MATCHES ".java")
|
||||
endforeach(_JAVA_SOURCE_FILE)
|
||||
|
||||
# create an empty java_class_filelist
|
||||
if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
|
||||
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
|
||||
endif()
|
||||
|
||||
if (_JAVA_COMPILE_FILES)
|
||||
# Compile the java files and create a list of class files
|
||||
add_custom_command(
|
||||
# NOTE: this command generates an artificial dependency file
|
||||
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
COMMAND ${Java_JAVAC_EXECUTABLE}
|
||||
${CMAKE_JAVA_COMPILE_FLAGS}
|
||||
-classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
|
||||
-d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
${_JAVA_COMPILE_FILES}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
DEPENDS ${_JAVA_COMPILE_FILES}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
-DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
|
||||
-P ${_JAVA_CLASS_FILELIST_SCRIPT}
|
||||
DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif (_JAVA_COMPILE_FILES)
|
||||
|
||||
# create the jar file
|
||||
set(_JAVA_JAR_OUTPUT_PATH
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME})
|
||||
if (CMAKE_JNI_TARGET)
|
||||
add_custom_command(
|
||||
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
|
||||
COMMAND ${Java_JAR_EXECUTABLE}
|
||||
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
|
||||
${_JAVA_RESOURCE_FILES} @java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
|
||||
)
|
||||
else ()
|
||||
add_custom_command(
|
||||
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
|
||||
COMMAND ${Java_JAR_EXECUTABLE}
|
||||
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
|
||||
${_JAVA_RESOURCE_FILES} @java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
|
||||
)
|
||||
endif (CMAKE_JNI_TARGET)
|
||||
|
||||
# Add the target and make sure we have the latest resource files.
|
||||
add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH})
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if (_JAVA_TARGET_OUTPUT_LINK)
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
|
||||
)
|
||||
|
||||
if (CMAKE_JNI_TARGET)
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JNI_SYMLINK
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
|
||||
)
|
||||
endif (CMAKE_JNI_TARGET)
|
||||
endif (_JAVA_TARGET_OUTPUT_LINK)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JAR_FILE
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
CLASSDIR
|
||||
${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
endfunction(add_jar)
|
||||
|
||||
function(INSTALL_JAR _TARGET_NAME _DESTINATION)
|
||||
get_property(__FILES
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
)
|
||||
|
||||
if (__FILES)
|
||||
install(
|
||||
FILES
|
||||
${__FILES}
|
||||
DESTINATION
|
||||
${_DESTINATION}
|
||||
)
|
||||
else (__FILES)
|
||||
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
|
||||
endif (__FILES)
|
||||
endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION)
|
||||
|
||||
function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
|
||||
get_property(__SYMLINK
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JNI_SYMLINK
|
||||
)
|
||||
|
||||
if (__SYMLINK)
|
||||
install(
|
||||
FILES
|
||||
${__SYMLINK}
|
||||
DESTINATION
|
||||
${_DESTINATION}
|
||||
)
|
||||
else (__SYMLINK)
|
||||
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
|
||||
endif (__SYMLINK)
|
||||
endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
|
||||
|
||||
function (find_jar VARIABLE)
|
||||
set(_jar_names)
|
||||
set(_jar_files)
|
||||
set(_jar_versions)
|
||||
set(_jar_paths
|
||||
/usr/share/java/
|
||||
/usr/local/share/java/
|
||||
${Java_JAR_PATHS})
|
||||
set(_jar_doc "NOTSET")
|
||||
|
||||
set(_state "name")
|
||||
|
||||
foreach (arg ${ARGN})
|
||||
if (${_state} STREQUAL "name")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "NAMES")
|
||||
set(_jar_names ${arg})
|
||||
if (_jar_doc STREQUAL "NOTSET")
|
||||
set(_jar_doc "Finding ${arg} jar")
|
||||
endif (_jar_doc STREQUAL "NOTSET")
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "versions")
|
||||
if (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "NAMES")
|
||||
set(_jar_versions ${_jar_versions} ${arg})
|
||||
endif (${arg} STREQUAL "NAMES")
|
||||
elseif (${_state} STREQUAL "names")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_names ${_jar_names} ${arg})
|
||||
if (_jar_doc STREQUAL "NOTSET")
|
||||
set(_jar_doc "Finding ${arg} jar")
|
||||
endif (_jar_doc STREQUAL "NOTSET")
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "paths")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_paths ${_jar_paths} ${arg})
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "doc")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_doc ${arg})
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
endif (${_state} STREQUAL "name")
|
||||
endforeach (arg ${ARGN})
|
||||
|
||||
if (NOT _jar_names)
|
||||
message(FATAL_ERROR "find_jar: No name to search for given")
|
||||
endif (NOT _jar_names)
|
||||
|
||||
foreach (jar_name ${_jar_names})
|
||||
foreach (version ${_jar_versions})
|
||||
set(_jar_files ${_jar_files} ${jar_name}-${version}.jar)
|
||||
endforeach (version ${_jar_versions})
|
||||
set(_jar_files ${_jar_files} ${jar_name}.jar)
|
||||
endforeach (jar_name ${_jar_names})
|
||||
|
||||
find_file(${VARIABLE}
|
||||
NAMES ${_jar_files}
|
||||
PATHS ${_jar_paths}
|
||||
DOC ${_jar_doc}
|
||||
NO_DEFAULT_PATH)
|
||||
endfunction (find_jar VARIABLE)
|
||||
|
||||
function(create_javadoc _target)
|
||||
set(_javadoc_packages)
|
||||
set(_javadoc_files)
|
||||
set(_javadoc_sourcepath)
|
||||
set(_javadoc_classpath)
|
||||
set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc")
|
||||
set(_javadoc_doctitle)
|
||||
set(_javadoc_windowtitle)
|
||||
set(_javadoc_author FALSE)
|
||||
set(_javadoc_version FALSE)
|
||||
set(_javadoc_use FALSE)
|
||||
|
||||
set(_state "package")
|
||||
|
||||
foreach (arg ${ARGN})
|
||||
if (${_state} STREQUAL "package")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_packages ${arg})
|
||||
set(_state "packages")
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "packages")
|
||||
if (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_packages ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "files")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_files ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "sourcepath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_sourcepath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "classpath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_classpath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "installpath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_installpath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "doctitle")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_doctitle ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "windowtitle")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_windowtitle ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "author")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_author ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "use")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_use ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "version")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_version ${arg})
|
||||
endif ()
|
||||
endif (${_state} STREQUAL "package")
|
||||
endforeach (arg ${ARGN})
|
||||
|
||||
set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target})
|
||||
set(_javadoc_options -d ${_javadoc_builddir})
|
||||
|
||||
if (_javadoc_sourcepath)
|
||||
set(_start TRUE)
|
||||
foreach(_path ${_javadoc_sourcepath})
|
||||
if (_start)
|
||||
set(_sourcepath ${_path})
|
||||
set(_start FALSE)
|
||||
else (_start)
|
||||
set(_sourcepath ${_sourcepath}:${_path})
|
||||
endif (_start)
|
||||
endforeach(_path ${_javadoc_sourcepath})
|
||||
set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath})
|
||||
endif (_javadoc_sourcepath)
|
||||
|
||||
if (_javadoc_classpath)
|
||||
set(_start TRUE)
|
||||
foreach(_path ${_javadoc_classpath})
|
||||
if (_start)
|
||||
set(_classpath ${_path})
|
||||
set(_start FALSE)
|
||||
else (_start)
|
||||
set(_classpath ${_classpath}:${_path})
|
||||
endif (_start)
|
||||
endforeach(_path ${_javadoc_classpath})
|
||||
set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}")
|
||||
endif (_javadoc_classpath)
|
||||
|
||||
if (_javadoc_doctitle)
|
||||
set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}')
|
||||
endif (_javadoc_doctitle)
|
||||
|
||||
if (_javadoc_windowtitle)
|
||||
set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}')
|
||||
endif (_javadoc_windowtitle)
|
||||
|
||||
if (_javadoc_author)
|
||||
set(_javadoc_options ${_javadoc_options} -author)
|
||||
endif (_javadoc_author)
|
||||
|
||||
if (_javadoc_use)
|
||||
set(_javadoc_options ${_javadoc_options} -use)
|
||||
endif (_javadoc_use)
|
||||
|
||||
if (_javadoc_version)
|
||||
set(_javadoc_options ${_javadoc_options} -version)
|
||||
endif (_javadoc_version)
|
||||
|
||||
add_custom_target(${_target}_javadoc ALL
|
||||
COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options}
|
||||
${_javadoc_files}
|
||||
${_javadoc_packages}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${_javadoc_builddir}
|
||||
DESTINATION ${_javadoc_installpath}
|
||||
)
|
||||
endfunction(create_javadoc)
|
52
launcher/UseJavaClassFilelist.cmake
Normal file
52
launcher/UseJavaClassFilelist.cmake
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# This script create a list of compiled Java class files to be added to a
|
||||
# jar file. This avoids including cmake files which get created in the
|
||||
# binary directory.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
||||
if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
|
||||
set(_JAVA_GLOBBED_FILES)
|
||||
if (CMAKE_JAR_CLASSES_PREFIX)
|
||||
foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
|
||||
message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}")
|
||||
|
||||
file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class")
|
||||
if (_JAVA_GLOBBED_TMP_FILES)
|
||||
list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES})
|
||||
endif (_JAVA_GLOBBED_TMP_FILES)
|
||||
endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
|
||||
else()
|
||||
file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class")
|
||||
endif (CMAKE_JAR_CLASSES_PREFIX)
|
||||
|
||||
set(_JAVA_CLASS_FILES)
|
||||
# file(GLOB_RECURSE foo RELATIVE) is broken so we need this.
|
||||
foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
|
||||
file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE})
|
||||
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n)
|
||||
endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
|
||||
|
||||
# write to file
|
||||
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES})
|
||||
|
||||
else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
message(SEND_ERROR "FATAL: Java class output path doesn't exist")
|
||||
endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
else (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
||||
message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
|
||||
endif (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
32
launcher/UseJavaSymlinks.cmake
Normal file
32
launcher/UseJavaSymlinks.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# Helper script for UseJava.cmake
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
|
||||
if (_JAVA_TARGET_OUTPUT_NAME)
|
||||
find_program(LN_EXECUTABLE
|
||||
NAMES
|
||||
ln
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}"
|
||||
WORKING_DIRECTORY ${_JAVA_TARGET_DIR}
|
||||
)
|
||||
else (_JAVA_TARGET_OUTPUT_NAME)
|
||||
message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME")
|
||||
endif (_JAVA_TARGET_OUTPUT_NAME)
|
||||
endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
|
154
launcher/net/minecraft/Launcher.java
Normal file
154
launcher/net/minecraft/Launcher.java
Normal file
@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright 2012 MultiMC Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package net.minecraft;
|
||||
|
||||
import java.util.TreeMap;
|
||||
import java.util.Map;
|
||||
import java.net.URL;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.applet.Applet;
|
||||
import java.applet.AppletStub;
|
||||
|
||||
public class Launcher extends Applet implements AppletStub
|
||||
{
|
||||
private Applet wrappedApplet;
|
||||
private URL documentBase;
|
||||
private boolean active = false;
|
||||
private final Map<String, String> params;
|
||||
|
||||
public Launcher(Applet applet, URL documentBase)
|
||||
{
|
||||
params = new TreeMap<String, String>();
|
||||
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(applet, "Center");
|
||||
this.wrappedApplet = applet;
|
||||
this.documentBase = documentBase;
|
||||
}
|
||||
|
||||
public void setParameter(String name, String value)
|
||||
{
|
||||
params.put(name, value);
|
||||
}
|
||||
|
||||
public void replace(Applet applet)
|
||||
{
|
||||
this.wrappedApplet = applet;
|
||||
|
||||
applet.setStub(this);
|
||||
applet.setSize(getWidth(), getHeight());
|
||||
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(applet, "Center");
|
||||
|
||||
applet.init();
|
||||
active = true;
|
||||
applet.start();
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String name)
|
||||
{
|
||||
String param = params.get(name);
|
||||
if (param != null)
|
||||
return param;
|
||||
try
|
||||
{
|
||||
return super.getParameter(name);
|
||||
} catch (Exception ignore){}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appletResize(int width, int height)
|
||||
{
|
||||
wrappedApplet.resize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height)
|
||||
{
|
||||
wrappedApplet.resize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(Dimension d)
|
||||
{
|
||||
wrappedApplet.resize(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
if (wrappedApplet != null)
|
||||
{
|
||||
wrappedApplet.init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
wrappedApplet.start();
|
||||
active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
wrappedApplet.stop();
|
||||
active = false;
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
wrappedApplet.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getCodeBase() {
|
||||
return wrappedApplet.getCodeBase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getDocumentBase()
|
||||
{
|
||||
return documentBase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b)
|
||||
{
|
||||
super.setVisible(b);
|
||||
wrappedApplet.setVisible(b);
|
||||
}
|
||||
public void update(Graphics paramGraphics)
|
||||
{
|
||||
}
|
||||
public void paint(Graphics paramGraphics)
|
||||
{
|
||||
}
|
||||
}
|
176
launcher/org/simplericity/macify/eawt/Application.java
Normal file
176
launcher/org/simplericity/macify/eawt/Application.java
Normal file
@ -0,0 +1,176 @@
|
||||
package org.simplericity.macify.eawt;
|
||||
|
||||
/*
|
||||
* Copyright 2007 Eirik Bjorsnos.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* The Macify Library API interface provides integration with the OS X platform for Java Applications.
|
||||
* The API includes a facade to the
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/index.html">
|
||||
* Apple Java Extensions API
|
||||
* </a>.
|
||||
* Additionally, it provides access to several useful methods in the Cocoa NSApplication API.
|
||||
*
|
||||
* The default implementation of this interface is {@link org.simplericity.macify.eawt.DefaultApplication}.
|
||||
*/
|
||||
public interface Application {
|
||||
|
||||
static int REQUEST_USER_ATTENTION_TYPE_CRITICAL = 1 ;
|
||||
static int REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL = 2 ;
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#addAboutMenuItem()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void addAboutMenuItem();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#addApplicationListener(com.apple.eawt.ApplicationListener)">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void addApplicationListener(ApplicationListener applicationListener);
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#addPreferencesMenuItem()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void addPreferencesMenuItem();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledAboutMenu()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
boolean getEnabledAboutMenu();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledPreferencesMenu()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
boolean getEnabledPreferencesMenu();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#isAboutMenuItemPresent()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
boolean isAboutMenuItemPresent();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#isPreferencesMenuItemPresent()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
boolean isPreferencesMenuItemPresent();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#removeAboutMenuItem()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void removeAboutMenuItem();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#removeApplicationListener(com.apple.eawt.ApplicationListener)">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void removeApplicationListener(ApplicationListener applicationListener);
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#removePreferencesMenuItem()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void removePreferencesMenuItem();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledAboutMenu()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void setEnabledAboutMenu(boolean enabled);
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledPreferencesMenu()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
void setEnabledPreferencesMenu(boolean enabled);
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getMouseLocationOnScreen()">
|
||||
* Apple's API
|
||||
* </a>.
|
||||
*/
|
||||
Point getMouseLocationOnScreen();
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/index.html#//apple_ref/doc/uid/TP40004004">
|
||||
* Apple's NSApplication Class Reference
|
||||
* </a>.
|
||||
* @param type on of {@link #REQUEST_USER_ATTENTION_TYPE_CRITICAL} or {@link #REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL}.
|
||||
*/
|
||||
int requestUserAttention(int type);
|
||||
|
||||
/**
|
||||
* See
|
||||
* <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/index.html#//apple_ref/doc/uid/TP40004004">
|
||||
* Apple's NSApplication Class Reference
|
||||
* </a>
|
||||
*/
|
||||
void cancelUserAttentionRequest(int request);
|
||||
|
||||
/**
|
||||
* Update the application's icon image
|
||||
* @param image
|
||||
*/
|
||||
void setApplicationIconImage(BufferedImage image);
|
||||
|
||||
/**
|
||||
* Get the application's icon image.
|
||||
*/
|
||||
BufferedImage getApplicationIconImage();
|
||||
|
||||
/**
|
||||
* Determines whether the application is running on a Mac AND the Apple Extensions API classes are available.
|
||||
* @return
|
||||
*/
|
||||
boolean isMac();
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.simplericity.macify.eawt;
|
||||
|
||||
/*
|
||||
* Copyright 2007 Eirik Bjorsnos.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public class ApplicationAdapter implements ApplicationListener {
|
||||
|
||||
public void handleQuit(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void handleAbout(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void handleOpenApplication(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void handleOpenFile(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void handlePreferences(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void handlePrintFile(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void handleReOpenApplication(ApplicationEvent event) {
|
||||
|
||||
}
|
||||
}
|
25
launcher/org/simplericity/macify/eawt/ApplicationEvent.java
Normal file
25
launcher/org/simplericity/macify/eawt/ApplicationEvent.java
Normal file
@ -0,0 +1,25 @@
|
||||
package org.simplericity.macify.eawt;
|
||||
|
||||
/*
|
||||
* Copyright 2007 Eirik Bjorsnos.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public interface ApplicationEvent {
|
||||
String getFilename();
|
||||
boolean isHandled();
|
||||
void setHandled(boolean handled);
|
||||
Object getSource();
|
||||
String toString();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package org.simplericity.macify.eawt;
|
||||
|
||||
/*
|
||||
* Copyright 2007 Eirik Bjorsnos.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public interface ApplicationListener {
|
||||
void handleAbout(ApplicationEvent event);
|
||||
void handleOpenApplication(ApplicationEvent event);
|
||||
void handleOpenFile(ApplicationEvent event);
|
||||
void handlePreferences(ApplicationEvent event);
|
||||
void handlePrintFile(ApplicationEvent event);
|
||||
void handleQuit(ApplicationEvent event);
|
||||
void handleReOpenApplication(ApplicationEvent event);
|
||||
}
|
418
launcher/org/simplericity/macify/eawt/DefaultApplication.java
Normal file
418
launcher/org/simplericity/macify/eawt/DefaultApplication.java
Normal file
@ -0,0 +1,418 @@
|
||||
package org.simplericity.macify.eawt;
|
||||
|
||||
/*
|
||||
* Copyright 2007 Eirik Bjorsnos.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Implements Application by calling the Mac OS X API through reflection.
|
||||
* If this class is used on a non-OS X platform the operations will have no effect or they will simulate
|
||||
* what the Apple API would do for those who manipulate state. ({@link #setEnabledAboutMenu(boolean)} etc.)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class DefaultApplication implements Application {
|
||||
|
||||
private Object application;
|
||||
private Class applicationListenerClass;
|
||||
|
||||
Map listenerMap = Collections.synchronizedMap(new HashMap<Object, Object>());
|
||||
private boolean enabledAboutMenu = true;
|
||||
private boolean enabledPreferencesMenu;
|
||||
private boolean aboutMenuItemPresent = true;
|
||||
private boolean preferencesMenuItemPresent;
|
||||
private ClassLoader classLoader;
|
||||
|
||||
public DefaultApplication() {
|
||||
try {
|
||||
final File file = new File("/System/Library/Java");
|
||||
if (file.exists()) {
|
||||
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
Class clc = scl.getClass();
|
||||
if (URLClassLoader.class.isAssignableFrom(clc)) {
|
||||
Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
|
||||
addUrl.setAccessible(true);
|
||||
addUrl.invoke(scl, new Object[]{file.toURI().toURL()});
|
||||
}
|
||||
}
|
||||
|
||||
Class appClass = Class.forName("com.apple.eawt.Application");
|
||||
application = appClass.getMethod("getApplication", new Class[0]).invoke(null, new Object[0]);
|
||||
applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
|
||||
} catch (ClassNotFoundException e) {
|
||||
application = null;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isMac() {
|
||||
return application != null;
|
||||
}
|
||||
|
||||
public void addAboutMenuItem() {
|
||||
if (isMac()) {
|
||||
callMethod(application, "addAboutMenuItem");
|
||||
} else {
|
||||
this.aboutMenuItemPresent = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void addApplicationListener(ApplicationListener applicationListener) {
|
||||
|
||||
if (!Modifier.isPublic(applicationListener.getClass().getModifiers())) {
|
||||
throw new IllegalArgumentException("ApplicationListener must be a public class");
|
||||
}
|
||||
if (isMac()) {
|
||||
Object listener = Proxy.newProxyInstance(getClass().getClassLoader(),
|
||||
new Class[]{applicationListenerClass},
|
||||
new ApplicationListenerInvocationHandler(applicationListener));
|
||||
|
||||
callMethod(application, "addApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener});
|
||||
listenerMap.put(applicationListener, listener);
|
||||
} else {
|
||||
listenerMap.put(applicationListener, applicationListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPreferencesMenuItem() {
|
||||
if (isMac()) {
|
||||
callMethod("addPreferencesMenuItem");
|
||||
} else {
|
||||
this.preferencesMenuItemPresent = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getEnabledAboutMenu() {
|
||||
if (isMac()) {
|
||||
return callMethod("getEnabledAboutMenu").equals(Boolean.TRUE);
|
||||
} else {
|
||||
return enabledAboutMenu;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getEnabledPreferencesMenu() {
|
||||
if (isMac()) {
|
||||
Object result = callMethod("getEnabledPreferencesMenu");
|
||||
return result.equals(Boolean.TRUE);
|
||||
} else {
|
||||
return enabledPreferencesMenu;
|
||||
}
|
||||
}
|
||||
|
||||
public Point getMouseLocationOnScreen() {
|
||||
if (isMac()) {
|
||||
try {
|
||||
Method method = application.getClass().getMethod("getMouseLocationOnScreen", new Class[0]);
|
||||
return (Point) method.invoke(null, new Object[0]);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
return new Point(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAboutMenuItemPresent() {
|
||||
if (isMac()) {
|
||||
return callMethod("isAboutMenuItemPresent").equals(Boolean.TRUE);
|
||||
} else {
|
||||
return aboutMenuItemPresent;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPreferencesMenuItemPresent() {
|
||||
if (isMac()) {
|
||||
return callMethod("isPreferencesMenuItemPresent").equals(Boolean.TRUE);
|
||||
} else {
|
||||
return this.preferencesMenuItemPresent;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAboutMenuItem() {
|
||||
if (isMac()) {
|
||||
callMethod("removeAboutMenuItem");
|
||||
} else {
|
||||
this.aboutMenuItemPresent = false;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeApplicationListener(ApplicationListener applicationListener) {
|
||||
if (isMac()) {
|
||||
Object listener = listenerMap.get(applicationListener);
|
||||
callMethod(application, "removeApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener});
|
||||
|
||||
}
|
||||
listenerMap.remove(applicationListener);
|
||||
}
|
||||
|
||||
public void removePreferencesMenuItem() {
|
||||
if (isMac()) {
|
||||
callMethod("removeAboutMenuItem");
|
||||
} else {
|
||||
this.preferencesMenuItemPresent = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabledAboutMenu(boolean enabled) {
|
||||
if (isMac()) {
|
||||
callMethod(application, "setEnabledAboutMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)});
|
||||
} else {
|
||||
this.enabledAboutMenu = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabledPreferencesMenu(boolean enabled) {
|
||||
if (isMac()) {
|
||||
callMethod(application, "setEnabledPreferencesMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)});
|
||||
} else {
|
||||
this.enabledPreferencesMenu = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int requestUserAttention(int type) {
|
||||
if (type != REQUEST_USER_ATTENTION_TYPE_CRITICAL && type != REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL) {
|
||||
throw new IllegalArgumentException("Requested user attention type is not allowed: " + type);
|
||||
}
|
||||
try {
|
||||
Object application = getNSApplication();
|
||||
Field critical = application.getClass().getField("UserAttentionRequestCritical");
|
||||
Field informational = application.getClass().getField("UserAttentionRequestInformational");
|
||||
Field actual = type == REQUEST_USER_ATTENTION_TYPE_CRITICAL ? critical : informational;
|
||||
|
||||
return ((Integer) application.getClass().getMethod("requestUserAttention", new Class[]{Integer.TYPE}).invoke(application, new Object[]{actual.get(null)})).intValue();
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
return -1;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelUserAttentionRequest(int request) {
|
||||
try {
|
||||
Object application = getNSApplication();
|
||||
application.getClass().getMethod("cancelUserAttentionRequest", new Class[]{Integer.TYPE}).invoke(application, new Object[]{new Integer(request)});
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Nada
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getNSApplication() throws ClassNotFoundException {
|
||||
try {
|
||||
Class applicationClass = Class.forName("com.apple.cocoa.application.NSApplication");
|
||||
return applicationClass.getMethod("sharedApplication", new Class[0]).invoke(null, new Object[0]);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setApplicationIconImage(BufferedImage image) {
|
||||
if (isMac()) {
|
||||
try {
|
||||
Method setDockIconImage = application.getClass().getMethod("setDockIconImage", Image.class);
|
||||
|
||||
try {
|
||||
setDockIconImage.invoke(application, image);
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
} catch (InvocationTargetException e) {
|
||||
|
||||
}
|
||||
} catch (NoSuchMethodException mnfe) {
|
||||
|
||||
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
try {
|
||||
ImageIO.write(image, "png", stream);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData");
|
||||
Constructor constructor = nsDataClass.getConstructor(new Class[]{new byte[0].getClass()});
|
||||
|
||||
Object nsData = constructor.newInstance(new Object[]{stream.toByteArray()});
|
||||
|
||||
Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage");
|
||||
Object nsImage = nsImageClass.getConstructor(new Class[]{nsDataClass}).newInstance(new Object[]{nsData});
|
||||
|
||||
Object application = getNSApplication();
|
||||
|
||||
application.getClass().getMethod("setApplicationIconImage", new Class[]{nsImageClass}).invoke(application, new Object[]{nsImage});
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage getApplicationIconImage() {
|
||||
if (isMac()) {
|
||||
|
||||
try {
|
||||
Method getDockIconImage = application.getClass().getMethod("getDockIconImage");
|
||||
try {
|
||||
return (BufferedImage) getDockIconImage.invoke(application);
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
} catch (InvocationTargetException e) {
|
||||
|
||||
}
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
|
||||
try {
|
||||
Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData");
|
||||
Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage");
|
||||
Object application = getNSApplication();
|
||||
Object nsImage = application.getClass().getMethod("applicationIconImage", new Class[0]).invoke(application, new Object[0]);
|
||||
|
||||
Object nsData = nsImageClass.getMethod("TIFFRepresentation", new Class[0]).invoke(nsImage, new Object[0]);
|
||||
|
||||
Integer length = (Integer) nsDataClass.getMethod("length", new Class[0]).invoke(nsData, new Object[0]);
|
||||
byte[] bytes = (byte[]) nsDataClass.getMethod("bytes", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(nsData, new Object[]{Integer.valueOf(0), length});
|
||||
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
|
||||
return image;
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object callMethod(String methodname) {
|
||||
return callMethod(application, methodname, new Class[0], new Object[0]);
|
||||
}
|
||||
|
||||
private Object callMethod(Object object, String methodname) {
|
||||
return callMethod(object, methodname, new Class[0], new Object[0]);
|
||||
}
|
||||
|
||||
private Object callMethod(Object object, String methodname, Class[] classes, Object[] arguments) {
|
||||
try {
|
||||
if (classes == null) {
|
||||
classes = new Class[arguments.length];
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
classes[i] = arguments[i].getClass();
|
||||
|
||||
}
|
||||
}
|
||||
Method addListnerMethod = object.getClass().getMethod(methodname, classes);
|
||||
return addListnerMethod.invoke(object, arguments);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationListenerInvocationHandler implements InvocationHandler {
|
||||
private ApplicationListener applicationListener;
|
||||
|
||||
ApplicationListenerInvocationHandler(ApplicationListener applicationListener) {
|
||||
this.applicationListener = applicationListener;
|
||||
}
|
||||
|
||||
public Object invoke(Object object, Method appleMethod, Object[] objects) throws Throwable {
|
||||
|
||||
ApplicationEvent event = createApplicationEvent(objects[0]);
|
||||
try {
|
||||
Method method = applicationListener.getClass().getMethod(appleMethod.getName(), new Class[]{ApplicationEvent.class});
|
||||
return method.invoke(applicationListener, new Object[]{event});
|
||||
} catch (NoSuchMethodException e) {
|
||||
if (appleMethod.getName().equals("equals") && objects.length == 1) {
|
||||
return Boolean.valueOf(object == objects[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ApplicationEvent createApplicationEvent(final Object appleApplicationEvent) {
|
||||
return (ApplicationEvent) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ApplicationEvent.class}, new InvocationHandler() {
|
||||
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
|
||||
return appleApplicationEvent.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(appleApplicationEvent, objects);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -26,4 +26,7 @@
|
||||
<file alias="squarecreeper">resources/icons/instances/squarecreeper.svg</file>
|
||||
<file alias="steve">resources/icons/instances/steve.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="launcher">
|
||||
<file alias="launcherjar">resources/MultiMCLauncher.jar</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
49
multimc_pragma.h
Normal file
49
multimc_pragma.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
// This is here to keep MSVC from spamming the build output with nonsense
|
||||
// Call it public domain.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
// C4251 can be ignored in Microsoft Visual C++ 2005 if you are deriving from a type
|
||||
// in the Standard C++ Library, compiling a debug release (/MTd) and where the compiler
|
||||
// error message refers to _Container_base.
|
||||
// Shows up when you export classes that use STL types. Stupid.
|
||||
// #pragma warning( disable: 4251 )
|
||||
|
||||
// C4273 - inconsistent DLL linkage. how about none?
|
||||
#pragma warning( disable: 4273 )
|
||||
|
||||
// don't display bogus 'deprecation' and 'unsafe' warnings.
|
||||
// See the idiocy: http://msdn.microsoft.com/en-us/magazine/cc163794.aspx
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _SCL_SECURE_NO_DEPRECATE
|
||||
// Let me demonstrate:
|
||||
/**
|
||||
* [peterix@peterix dfhack]$ man wcscpy_s
|
||||
* No manual entry for wcscpy_s
|
||||
*
|
||||
* Proprietary extensions.
|
||||
*/
|
||||
//'function': was declared deprecated
|
||||
#pragma warning( disable: 4996 )
|
||||
|
||||
// disable stupid - forcing value to bool 'true' or 'false' (performance warning).
|
||||
// When I do this, it's intentional. Always.
|
||||
#pragma warning( disable: 4800 )
|
||||
|
||||
// disable more stupid - The compiler ignored an unrecognized pragma. GOOD JOB, DON'T SPAM ME WITH THAT
|
||||
#pragma warning( disable: 4068 )
|
||||
|
||||
// no signed value outside enum range bs
|
||||
//#pragma warning( disable: 4341)
|
||||
|
||||
// just shut up already - conversion between types loses precision
|
||||
//#pragma warning( disable: 4244)
|
||||
|
||||
// signed/unsigned mismatch
|
||||
//#pragma warning( disable: 4018)
|
||||
|
||||
// nonstandard extension used: enum 'df::whatever::etc' used in qualified name
|
||||
//#pragma warning( disable: 4482)
|
||||
#endif
|
14
patchlib/CMakeLists.txt
Normal file
14
patchlib/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
project(patchlib C)
|
||||
|
||||
set(SRCS
|
||||
blocksort.c
|
||||
huffman.c
|
||||
crctable.c
|
||||
randtable.c
|
||||
compress.c
|
||||
decompress.c
|
||||
bzlib.c
|
||||
bspatch.c
|
||||
)
|
||||
|
||||
add_library(patchlib STATIC ${SRCS})
|
42
patchlib/LICENSE-bzip2
Normal file
42
patchlib/LICENSE-bzip2
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
This program, "bzip2", the associated library "libbzip2", and all
|
||||
documentation, are copyright (C) 1996-2010 Julian R Seward. All
|
||||
rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Julian Seward, jseward@bzip.org
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
|
||||
--------------------------------------------------------------------------
|
1095
patchlib/blocksort.c
Normal file
1095
patchlib/blocksort.c
Normal file
File diff suppressed because it is too large
Load Diff
303
patchlib/bspatch.c
Normal file
303
patchlib/bspatch.c
Normal file
@ -0,0 +1,303 @@
|
||||
/*-
|
||||
* Copyright 2003-2005 Colin Percival
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// bogus 'secure' nonsense
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
// bogus signed/unsigned mismatch
|
||||
#pragma warning( disable: 4018)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sys/types.h>
|
||||
#define ssize_t size_t
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined __APPLE__ && defined __MACH__
|
||||
typedef unsigned char u_char;
|
||||
#endif
|
||||
|
||||
#include "bzlib.h"
|
||||
#include "bspatch.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static off_t offtin(u_char *buf)
|
||||
{
|
||||
off_t y;
|
||||
|
||||
y=buf[7]&0x7F;
|
||||
y=y*256;y+=buf[6];
|
||||
y=y*256;y+=buf[5];
|
||||
y=y*256;y+=buf[4];
|
||||
y=y*256;y+=buf[3];
|
||||
y=y*256;y+=buf[2];
|
||||
y=y*256;y+=buf[1];
|
||||
y=y*256;y+=buf[0];
|
||||
|
||||
if(buf[7]&0x80) y=-y;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
int bspatch(const char * oldfile, const char * newfile, const char * patchfile)
|
||||
{
|
||||
FILE * f, * cpf, * dpf, * epf;
|
||||
BZFILE * cpfbz2, * dpfbz2, * epfbz2;
|
||||
int cbz2err, dbz2err, ebz2err;
|
||||
FILE * temp;
|
||||
ssize_t oldsize,newsize;
|
||||
ssize_t bzctrllen,bzdatalen;
|
||||
unsigned char header[32],buf[8];
|
||||
unsigned char *old_contents;
|
||||
unsigned char *new_contents;
|
||||
off_t oldpos,newpos;
|
||||
off_t ctrl[3];
|
||||
off_t lenread;
|
||||
off_t i;
|
||||
|
||||
/* Open patch file */
|
||||
if ((f = fopen(patchfile, "rb")) == NULL)
|
||||
{
|
||||
//err(1, "fopen(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
|
||||
/*
|
||||
File format:
|
||||
0 8 "BSDIFF40"
|
||||
8 8 X
|
||||
16 8 Y
|
||||
24 8 sizeof(newfile)
|
||||
32 X bzip2(control block)
|
||||
32+X Y bzip2(diff block)
|
||||
32+X+Y ??? bzip2(extra block)
|
||||
with control block a set of triples (x,y,z) meaning "add x bytes
|
||||
from oldfile to x bytes from the diff block; copy y bytes from the
|
||||
extra block; seek forwards in oldfile by z bytes".
|
||||
*/
|
||||
|
||||
/* Read header */
|
||||
if (fread(header, 1, 32, f) < 32)
|
||||
{
|
||||
if (feof(f))
|
||||
{
|
||||
//errx(1, "Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
//err(1, "fread(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
|
||||
/* Check for appropriate magic */
|
||||
if (memcmp(header, "BSDIFF40", 8) != 0)
|
||||
{
|
||||
//errx(1, "Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
|
||||
/* Read lengths from header */
|
||||
bzctrllen=offtin(header+8);
|
||||
bzdatalen=offtin(header+16);
|
||||
newsize=offtin(header+24);
|
||||
if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
|
||||
{
|
||||
//errx(1,"Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
|
||||
/* Close patch file and re-open it via libbzip2 at the right places */
|
||||
if (fclose(f))
|
||||
{
|
||||
//err(1, "fclose(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if ((cpf = fopen(patchfile, "rb")) == NULL)
|
||||
{
|
||||
//err(1, "fopen(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if (fseek(cpf, 32, SEEK_SET))
|
||||
{
|
||||
// err(1, "fseeko(%s, %lld)", argv[3], (long long)32);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
|
||||
{
|
||||
//errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if ((dpf = fopen(patchfile, "rb")) == NULL)
|
||||
{
|
||||
//err(1, "fopen(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if (fseek(dpf, 32 + bzctrllen, SEEK_SET))
|
||||
{
|
||||
//err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen));
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
|
||||
{
|
||||
//errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if ((epf = fopen(patchfile, "rb")) == NULL)
|
||||
{
|
||||
//err(1, "fopen(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
|
||||
{
|
||||
//err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen + bzdatalen));
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
|
||||
{
|
||||
//errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
|
||||
if((temp=fopen(oldfile,"rb")) == NULL)
|
||||
{
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if((fseek(temp,0,SEEK_END))!=0)
|
||||
{
|
||||
return ERR_OTHER;
|
||||
}
|
||||
oldsize = ftell(temp);
|
||||
if((old_contents=malloc(oldsize+1))==NULL)
|
||||
{
|
||||
return ERR_OTHER;
|
||||
}
|
||||
rewind(temp);
|
||||
if(fread(old_contents,oldsize,1,temp)!=1)
|
||||
{
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if(fclose(temp)==EOF)
|
||||
{
|
||||
return ERR_OTHER;
|
||||
}
|
||||
if((new_contents=malloc(newsize+1))==NULL)
|
||||
{
|
||||
//err(1,NULL);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
|
||||
oldpos=0;newpos=0;
|
||||
while(newpos<newsize)
|
||||
{
|
||||
/* Read control data */
|
||||
for(i=0;i<=2;i++) {
|
||||
lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
|
||||
if ((lenread < 8) || ((cbz2err != BZ_OK) && (cbz2err != BZ_STREAM_END)))
|
||||
{
|
||||
//errx(1, "Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
ctrl[i]=offtin(buf);
|
||||
};
|
||||
|
||||
/* Sanity-check */
|
||||
if(newpos+ctrl[0]>newsize)
|
||||
{
|
||||
//errx(1,"Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
|
||||
/* Read diff string */
|
||||
lenread = BZ2_bzRead(&dbz2err, dpfbz2, new_contents + newpos, ctrl[0]);
|
||||
if ((lenread < ctrl[0]) || ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
|
||||
{
|
||||
//errx(1, "Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
|
||||
/* Add old data to diff string */
|
||||
for(i=0;i<ctrl[0];i++)
|
||||
{
|
||||
if((oldpos+i>=0) && (oldpos+i<oldsize))
|
||||
{
|
||||
new_contents[newpos+i]+=old_contents[oldpos+i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust pointers */
|
||||
newpos+=ctrl[0];
|
||||
oldpos+=ctrl[0];
|
||||
|
||||
/* Sanity-check */
|
||||
if(newpos+ctrl[1]>newsize)
|
||||
{
|
||||
//errx(1,"Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
|
||||
/* Read extra string */
|
||||
lenread = BZ2_bzRead(&ebz2err, epfbz2, new_contents + newpos, ctrl[1]);
|
||||
if ((lenread < ctrl[1]) || ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
|
||||
{
|
||||
//errx(1, "Corrupt patch\n");
|
||||
return ERR_CORRUPT_PATCH;
|
||||
}
|
||||
|
||||
/* Adjust pointers */
|
||||
newpos+=ctrl[1];
|
||||
oldpos+=ctrl[2];
|
||||
};
|
||||
|
||||
/* Clean up the bzip2 reads */
|
||||
BZ2_bzReadClose(&cbz2err, cpfbz2);
|
||||
BZ2_bzReadClose(&dbz2err, dpfbz2);
|
||||
BZ2_bzReadClose(&ebz2err, epfbz2);
|
||||
if (fclose(cpf) || fclose(dpf) || fclose(epf))
|
||||
{
|
||||
//err(1, "fclose(%s)", argv[3]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
|
||||
/* Write the new file */
|
||||
if(
|
||||
((temp=fopen(newfile,"wb"))==NULL) ||
|
||||
(fwrite(new_contents,newsize,1,temp)==0) ||
|
||||
(fclose(temp)==EOF)
|
||||
)
|
||||
{
|
||||
//err(1,"%s",argv[2]);
|
||||
return ERR_OTHER;
|
||||
}
|
||||
|
||||
free(new_contents);
|
||||
free(old_contents);
|
||||
|
||||
return ERR_NONE;
|
||||
}
|
27
patchlib/bspatch.h
Normal file
27
patchlib/bspatch.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _BSPATCH_H
|
||||
#define _BSPATCH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum BSPatchError
|
||||
{
|
||||
ERR_CORRUPT_PATCH,
|
||||
ERR_OTHER,
|
||||
ERR_NONE,
|
||||
};
|
||||
|
||||
/**
|
||||
* patch oldfile by using patchfile and write the output to newfile.
|
||||
*
|
||||
* Returns ERR_NONE if successful
|
||||
*/
|
||||
int bspatch(const char * oldfile, const char * newfile, const char * patchfile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
1579
patchlib/bzlib.c
Normal file
1579
patchlib/bzlib.c
Normal file
File diff suppressed because it is too large
Load Diff
283
patchlib/bzlib.h
Normal file
283
patchlib/bzlib.h
Normal file
@ -0,0 +1,283 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Public header file for the library. ---*/
|
||||
/*--- bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#ifndef _BZLIB_H
|
||||
#define _BZLIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BZ_RUN 0
|
||||
#define BZ_FLUSH 1
|
||||
#define BZ_FINISH 2
|
||||
|
||||
#define BZ_OK 0
|
||||
#define BZ_RUN_OK 1
|
||||
#define BZ_FLUSH_OK 2
|
||||
#define BZ_FINISH_OK 3
|
||||
#define BZ_STREAM_END 4
|
||||
#define BZ_SEQUENCE_ERROR (-1)
|
||||
#define BZ_PARAM_ERROR (-2)
|
||||
#define BZ_MEM_ERROR (-3)
|
||||
#define BZ_DATA_ERROR (-4)
|
||||
#define BZ_DATA_ERROR_MAGIC (-5)
|
||||
#define BZ_IO_ERROR (-6)
|
||||
#define BZ_UNEXPECTED_EOF (-7)
|
||||
#define BZ_OUTBUFF_FULL (-8)
|
||||
#define BZ_CONFIG_ERROR (-9)
|
||||
|
||||
typedef
|
||||
struct {
|
||||
char *next_in;
|
||||
unsigned int avail_in;
|
||||
unsigned int total_in_lo32;
|
||||
unsigned int total_in_hi32;
|
||||
|
||||
char *next_out;
|
||||
unsigned int avail_out;
|
||||
unsigned int total_out_lo32;
|
||||
unsigned int total_out_hi32;
|
||||
|
||||
void *state;
|
||||
|
||||
void *(*bzalloc)(void *,int,int);
|
||||
void (*bzfree)(void *,void *);
|
||||
void *opaque;
|
||||
}
|
||||
bz_stream;
|
||||
|
||||
|
||||
#ifndef BZ_IMPORT
|
||||
#define BZ_EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
/* Need a definitition for FILE */
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# ifdef small
|
||||
/* windows.h define small to char */
|
||||
# undef small
|
||||
# endif
|
||||
# ifdef BZ_EXPORT
|
||||
# define BZ_API(func) WINAPI func
|
||||
# define BZ_EXTERN extern
|
||||
# else
|
||||
/* import windows dll dynamically */
|
||||
# define BZ_API(func) (WINAPI * func)
|
||||
# define BZ_EXTERN
|
||||
# endif
|
||||
#else
|
||||
# define BZ_API(func) func
|
||||
# define BZ_EXTERN extern
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Core (low-level) library functions --*/
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
|
||||
bz_stream* strm,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompress) (
|
||||
bz_stream* strm,
|
||||
int action
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
|
||||
bz_stream* strm
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
|
||||
bz_stream *strm,
|
||||
int verbosity,
|
||||
int small
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
|
||||
bz_stream* strm
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
|
||||
bz_stream *strm
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*-- High(er) level library functions --*/
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
#define BZ_MAX_UNUSED 5000
|
||||
|
||||
typedef void BZFILE;
|
||||
|
||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
|
||||
int* bzerror,
|
||||
FILE* f,
|
||||
int verbosity,
|
||||
int small,
|
||||
void* unused,
|
||||
int nUnused
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
|
||||
int* bzerror,
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void** unused,
|
||||
int* nUnused
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzRead) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
|
||||
int* bzerror,
|
||||
FILE* f,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWrite) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
int abandon,
|
||||
unsigned int* nbytes_in,
|
||||
unsigned int* nbytes_out
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
|
||||
int* bzerror,
|
||||
BZFILE* b,
|
||||
int abandon,
|
||||
unsigned int* nbytes_in_lo32,
|
||||
unsigned int* nbytes_in_hi32,
|
||||
unsigned int* nbytes_out_lo32,
|
||||
unsigned int* nbytes_out_hi32
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Utility functions --*/
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
|
||||
char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int blockSize100k,
|
||||
int verbosity,
|
||||
int workFactor
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
|
||||
char* dest,
|
||||
unsigned int* destLen,
|
||||
char* source,
|
||||
unsigned int sourceLen,
|
||||
int small,
|
||||
int verbosity
|
||||
);
|
||||
|
||||
|
||||
/*--
|
||||
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
|
||||
to support better zlib compatibility.
|
||||
This code is not _officially_ part of libbzip2 (yet);
|
||||
I haven't tested it, documented it, or considered the
|
||||
threading-safeness of it.
|
||||
If this code breaks, please contact both Yoshioka and me.
|
||||
--*/
|
||||
|
||||
BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
|
||||
void
|
||||
);
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
|
||||
const char *path,
|
||||
const char *mode
|
||||
);
|
||||
|
||||
BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
|
||||
int fd,
|
||||
const char *mode
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzread) (
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzwrite) (
|
||||
BZFILE* b,
|
||||
void* buf,
|
||||
int len
|
||||
);
|
||||
|
||||
BZ_EXTERN int BZ_API(BZ2_bzflush) (
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN void BZ_API(BZ2_bzclose) (
|
||||
BZFILE* b
|
||||
);
|
||||
|
||||
BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
|
||||
BZFILE *b,
|
||||
int *errnum
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
510
patchlib/bzlib_private.h
Normal file
510
patchlib/bzlib_private.h
Normal file
@ -0,0 +1,510 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Private header file for the library. ---*/
|
||||
/*--- bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#ifndef _BZLIB_PRIVATE_H
|
||||
#define _BZLIB_PRIVATE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "bzlib.h"
|
||||
|
||||
|
||||
|
||||
/*-- General stuff. --*/
|
||||
|
||||
#define BZ_VERSION "1.0.6, 6-Sept-2010"
|
||||
|
||||
typedef char Char;
|
||||
typedef unsigned char Bool;
|
||||
typedef unsigned char UChar;
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#define True ((Bool)1)
|
||||
#define False ((Bool)0)
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __inline__ /* */
|
||||
#endif
|
||||
|
||||
#ifndef BZ_NO_STDIO
|
||||
|
||||
extern void BZ2_bz__AssertH__fail ( int errcode );
|
||||
#define AssertH(cond,errcode) \
|
||||
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
|
||||
|
||||
#if BZ_DEBUG
|
||||
#define AssertD(cond,msg) \
|
||||
{ if (!(cond)) { \
|
||||
fprintf ( stderr, \
|
||||
"\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
|
||||
exit(1); \
|
||||
}}
|
||||
#else
|
||||
#define AssertD(cond,msg) /* */
|
||||
#endif
|
||||
|
||||
#define VPrintf0(zf) \
|
||||
fprintf(stderr,zf)
|
||||
#define VPrintf1(zf,za1) \
|
||||
fprintf(stderr,zf,za1)
|
||||
#define VPrintf2(zf,za1,za2) \
|
||||
fprintf(stderr,zf,za1,za2)
|
||||
#define VPrintf3(zf,za1,za2,za3) \
|
||||
fprintf(stderr,zf,za1,za2,za3)
|
||||
#define VPrintf4(zf,za1,za2,za3,za4) \
|
||||
fprintf(stderr,zf,za1,za2,za3,za4)
|
||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
|
||||
fprintf(stderr,zf,za1,za2,za3,za4,za5)
|
||||
|
||||
#else
|
||||
|
||||
extern void bz_internal_error ( int errcode );
|
||||
#define AssertH(cond,errcode) \
|
||||
{ if (!(cond)) bz_internal_error ( errcode ); }
|
||||
#define AssertD(cond,msg) do { } while (0)
|
||||
#define VPrintf0(zf) do { } while (0)
|
||||
#define VPrintf1(zf,za1) do { } while (0)
|
||||
#define VPrintf2(zf,za1,za2) do { } while (0)
|
||||
#define VPrintf3(zf,za1,za2,za3) do { } while (0)
|
||||
#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
|
||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
|
||||
#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
|
||||
|
||||
|
||||
/*-- Header bytes. --*/
|
||||
|
||||
#define BZ_HDR_B 0x42 /* 'B' */
|
||||
#define BZ_HDR_Z 0x5a /* 'Z' */
|
||||
#define BZ_HDR_h 0x68 /* 'h' */
|
||||
#define BZ_HDR_0 0x30 /* '0' */
|
||||
|
||||
/*-- Constants for the back end. --*/
|
||||
|
||||
#define BZ_MAX_ALPHA_SIZE 258
|
||||
#define BZ_MAX_CODE_LEN 23
|
||||
|
||||
#define BZ_RUNA 0
|
||||
#define BZ_RUNB 1
|
||||
|
||||
#define BZ_N_GROUPS 6
|
||||
#define BZ_G_SIZE 50
|
||||
#define BZ_N_ITERS 4
|
||||
|
||||
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
|
||||
|
||||
|
||||
|
||||
/*-- Stuff for randomising repetitive blocks. --*/
|
||||
|
||||
extern Int32 BZ2_rNums[512];
|
||||
|
||||
#define BZ_RAND_DECLS \
|
||||
Int32 rNToGo; \
|
||||
Int32 rTPos \
|
||||
|
||||
#define BZ_RAND_INIT_MASK \
|
||||
s->rNToGo = 0; \
|
||||
s->rTPos = 0 \
|
||||
|
||||
#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
|
||||
|
||||
#define BZ_RAND_UPD_MASK \
|
||||
if (s->rNToGo == 0) { \
|
||||
s->rNToGo = BZ2_rNums[s->rTPos]; \
|
||||
s->rTPos++; \
|
||||
if (s->rTPos == 512) s->rTPos = 0; \
|
||||
} \
|
||||
s->rNToGo--;
|
||||
|
||||
|
||||
|
||||
/*-- Stuff for doing CRCs. --*/
|
||||
|
||||
extern UInt32 BZ2_crc32Table[256];
|
||||
|
||||
#define BZ_INITIALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = 0xffffffffL; \
|
||||
}
|
||||
|
||||
#define BZ_FINALISE_CRC(crcVar) \
|
||||
{ \
|
||||
crcVar = ~(crcVar); \
|
||||
}
|
||||
|
||||
#define BZ_UPDATE_CRC(crcVar,cha) \
|
||||
{ \
|
||||
crcVar = (crcVar << 8) ^ \
|
||||
BZ2_crc32Table[(crcVar >> 24) ^ \
|
||||
((UChar)cha)]; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-- States and modes for compression. --*/
|
||||
|
||||
#define BZ_M_IDLE 1
|
||||
#define BZ_M_RUNNING 2
|
||||
#define BZ_M_FLUSHING 3
|
||||
#define BZ_M_FINISHING 4
|
||||
|
||||
#define BZ_S_OUTPUT 1
|
||||
#define BZ_S_INPUT 2
|
||||
|
||||
#define BZ_N_RADIX 2
|
||||
#define BZ_N_QSORT 12
|
||||
#define BZ_N_SHELL 18
|
||||
#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
|
||||
|
||||
|
||||
|
||||
|
||||
/*-- Structure holding all the compression-side stuff. --*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream* strm;
|
||||
|
||||
/* mode this stream is in, and whether inputting */
|
||||
/* or outputting data */
|
||||
Int32 mode;
|
||||
Int32 state;
|
||||
|
||||
/* remembers avail_in when flush/finish requested */
|
||||
UInt32 avail_in_expect;
|
||||
|
||||
/* for doing the block sorting */
|
||||
UInt32* arr1;
|
||||
UInt32* arr2;
|
||||
UInt32* ftab;
|
||||
Int32 origPtr;
|
||||
|
||||
/* aliases for arr1 and arr2 */
|
||||
UInt32* ptr;
|
||||
UChar* block;
|
||||
UInt16* mtfv;
|
||||
UChar* zbits;
|
||||
|
||||
/* for deciding when to use the fallback sorting algorithm */
|
||||
Int32 workFactor;
|
||||
|
||||
/* run-length-encoding of the input */
|
||||
UInt32 state_in_ch;
|
||||
Int32 state_in_len;
|
||||
BZ_RAND_DECLS;
|
||||
|
||||
/* input and output limits and current posns */
|
||||
Int32 nblock;
|
||||
Int32 nblockMAX;
|
||||
Int32 numZ;
|
||||
Int32 state_out_pos;
|
||||
|
||||
/* map of bytes used in block */
|
||||
Int32 nInUse;
|
||||
Bool inUse[256];
|
||||
UChar unseqToSeq[256];
|
||||
|
||||
/* the buffer for bit stream creation */
|
||||
UInt32 bsBuff;
|
||||
Int32 bsLive;
|
||||
|
||||
/* block and combined CRCs */
|
||||
UInt32 blockCRC;
|
||||
UInt32 combinedCRC;
|
||||
|
||||
/* misc administratium */
|
||||
Int32 verbosity;
|
||||
Int32 blockNo;
|
||||
Int32 blockSize100k;
|
||||
|
||||
/* stuff for coding the MTF values */
|
||||
Int32 nMTF;
|
||||
Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
|
||||
UChar selector [BZ_MAX_SELECTORS];
|
||||
UChar selectorMtf[BZ_MAX_SELECTORS];
|
||||
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
/* second dimension: only 3 needed; 4 makes index calculations faster */
|
||||
UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
|
||||
|
||||
}
|
||||
EState;
|
||||
|
||||
|
||||
|
||||
/*-- externs for compression. --*/
|
||||
|
||||
extern void
|
||||
BZ2_blockSort ( EState* );
|
||||
|
||||
extern void
|
||||
BZ2_compressBlock ( EState*, Bool );
|
||||
|
||||
extern void
|
||||
BZ2_bsInitWrite ( EState* );
|
||||
|
||||
extern void
|
||||
BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
|
||||
|
||||
extern void
|
||||
BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
|
||||
|
||||
|
||||
|
||||
/*-- states for decompression. --*/
|
||||
|
||||
#define BZ_X_IDLE 1
|
||||
#define BZ_X_OUTPUT 2
|
||||
|
||||
#define BZ_X_MAGIC_1 10
|
||||
#define BZ_X_MAGIC_2 11
|
||||
#define BZ_X_MAGIC_3 12
|
||||
#define BZ_X_MAGIC_4 13
|
||||
#define BZ_X_BLKHDR_1 14
|
||||
#define BZ_X_BLKHDR_2 15
|
||||
#define BZ_X_BLKHDR_3 16
|
||||
#define BZ_X_BLKHDR_4 17
|
||||
#define BZ_X_BLKHDR_5 18
|
||||
#define BZ_X_BLKHDR_6 19
|
||||
#define BZ_X_BCRC_1 20
|
||||
#define BZ_X_BCRC_2 21
|
||||
#define BZ_X_BCRC_3 22
|
||||
#define BZ_X_BCRC_4 23
|
||||
#define BZ_X_RANDBIT 24
|
||||
#define BZ_X_ORIGPTR_1 25
|
||||
#define BZ_X_ORIGPTR_2 26
|
||||
#define BZ_X_ORIGPTR_3 27
|
||||
#define BZ_X_MAPPING_1 28
|
||||
#define BZ_X_MAPPING_2 29
|
||||
#define BZ_X_SELECTOR_1 30
|
||||
#define BZ_X_SELECTOR_2 31
|
||||
#define BZ_X_SELECTOR_3 32
|
||||
#define BZ_X_CODING_1 33
|
||||
#define BZ_X_CODING_2 34
|
||||
#define BZ_X_CODING_3 35
|
||||
#define BZ_X_MTF_1 36
|
||||
#define BZ_X_MTF_2 37
|
||||
#define BZ_X_MTF_3 38
|
||||
#define BZ_X_MTF_4 39
|
||||
#define BZ_X_MTF_5 40
|
||||
#define BZ_X_MTF_6 41
|
||||
#define BZ_X_ENDHDR_2 42
|
||||
#define BZ_X_ENDHDR_3 43
|
||||
#define BZ_X_ENDHDR_4 44
|
||||
#define BZ_X_ENDHDR_5 45
|
||||
#define BZ_X_ENDHDR_6 46
|
||||
#define BZ_X_CCRC_1 47
|
||||
#define BZ_X_CCRC_2 48
|
||||
#define BZ_X_CCRC_3 49
|
||||
#define BZ_X_CCRC_4 50
|
||||
|
||||
|
||||
|
||||
/*-- Constants for the fast MTF decoder. --*/
|
||||
|
||||
#define MTFA_SIZE 4096
|
||||
#define MTFL_SIZE 16
|
||||
|
||||
|
||||
|
||||
/*-- Structure holding all the decompression-side stuff. --*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
/* pointer back to the struct bz_stream */
|
||||
bz_stream* strm;
|
||||
|
||||
/* state indicator for this stream */
|
||||
Int32 state;
|
||||
|
||||
/* for doing the final run-length decoding */
|
||||
UChar state_out_ch;
|
||||
Int32 state_out_len;
|
||||
Bool blockRandomised;
|
||||
BZ_RAND_DECLS;
|
||||
|
||||
/* the buffer for bit stream reading */
|
||||
UInt32 bsBuff;
|
||||
Int32 bsLive;
|
||||
|
||||
/* misc administratium */
|
||||
Int32 blockSize100k;
|
||||
Bool smallDecompress;
|
||||
Int32 currBlockNo;
|
||||
Int32 verbosity;
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform */
|
||||
Int32 origPtr;
|
||||
UInt32 tPos;
|
||||
Int32 k0;
|
||||
Int32 unzftab[256];
|
||||
Int32 nblock_used;
|
||||
Int32 cftab[257];
|
||||
Int32 cftabCopy[257];
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform (FAST) */
|
||||
UInt32 *tt;
|
||||
|
||||
/* for undoing the Burrows-Wheeler transform (SMALL) */
|
||||
UInt16 *ll16;
|
||||
UChar *ll4;
|
||||
|
||||
/* stored and calculated CRCs */
|
||||
UInt32 storedBlockCRC;
|
||||
UInt32 storedCombinedCRC;
|
||||
UInt32 calculatedBlockCRC;
|
||||
UInt32 calculatedCombinedCRC;
|
||||
|
||||
/* map of bytes used in block */
|
||||
Int32 nInUse;
|
||||
Bool inUse[256];
|
||||
Bool inUse16[16];
|
||||
UChar seqToUnseq[256];
|
||||
|
||||
/* for decoding the MTF values */
|
||||
UChar mtfa [MTFA_SIZE];
|
||||
Int32 mtfbase[256 / MTFL_SIZE];
|
||||
UChar selector [BZ_MAX_SELECTORS];
|
||||
UChar selectorMtf[BZ_MAX_SELECTORS];
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
|
||||
Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 minLens[BZ_N_GROUPS];
|
||||
|
||||
/* save area for scalars in the main decompress code */
|
||||
Int32 save_i;
|
||||
Int32 save_j;
|
||||
Int32 save_t;
|
||||
Int32 save_alphaSize;
|
||||
Int32 save_nGroups;
|
||||
Int32 save_nSelectors;
|
||||
Int32 save_EOB;
|
||||
Int32 save_groupNo;
|
||||
Int32 save_groupPos;
|
||||
Int32 save_nextSym;
|
||||
Int32 save_nblockMAX;
|
||||
Int32 save_nblock;
|
||||
Int32 save_es;
|
||||
Int32 save_N;
|
||||
Int32 save_curr;
|
||||
Int32 save_zt;
|
||||
Int32 save_zn;
|
||||
Int32 save_zvec;
|
||||
Int32 save_zj;
|
||||
Int32 save_gSel;
|
||||
Int32 save_gMinlen;
|
||||
Int32* save_gLimit;
|
||||
Int32* save_gBase;
|
||||
Int32* save_gPerm;
|
||||
|
||||
}
|
||||
DState;
|
||||
|
||||
|
||||
|
||||
/*-- Macros for decompression. --*/
|
||||
|
||||
#define BZ_GET_FAST(cccc) \
|
||||
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
|
||||
s->tPos = s->tt[s->tPos]; \
|
||||
cccc = (UChar)(s->tPos & 0xff); \
|
||||
s->tPos >>= 8;
|
||||
|
||||
#define BZ_GET_FAST_C(cccc) \
|
||||
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||
if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
|
||||
c_tPos = c_tt[c_tPos]; \
|
||||
cccc = (UChar)(c_tPos & 0xff); \
|
||||
c_tPos >>= 8;
|
||||
|
||||
#define SET_LL4(i,n) \
|
||||
{ if (((i) & 0x1) == 0) \
|
||||
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
|
||||
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
|
||||
}
|
||||
|
||||
#define GET_LL4(i) \
|
||||
((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
|
||||
|
||||
#define SET_LL(i,n) \
|
||||
{ s->ll16[i] = (UInt16)(n & 0x0000ffff); \
|
||||
SET_LL4(i, n >> 16); \
|
||||
}
|
||||
|
||||
#define GET_LL(i) \
|
||||
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
|
||||
|
||||
#define BZ_GET_SMALL(cccc) \
|
||||
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||
if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
|
||||
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
|
||||
s->tPos = GET_LL(s->tPos);
|
||||
|
||||
|
||||
/*-- externs for decompression. --*/
|
||||
|
||||
extern Int32
|
||||
BZ2_indexIntoF ( Int32, Int32* );
|
||||
|
||||
extern Int32
|
||||
BZ2_decompress ( DState* );
|
||||
|
||||
extern void
|
||||
BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
|
||||
Int32, Int32, Int32 );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
|
||||
|
||||
#ifdef BZ_NO_STDIO
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end bzlib_private.h ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
672
patchlib/compress.c
Normal file
672
patchlib/compress.c
Normal file
@ -0,0 +1,672 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Compression machinery (not incl block sorting) ---*/
|
||||
/*--- compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
/* CHANGES
|
||||
0.9.0 -- original version.
|
||||
0.9.0a/b -- no changes in this file.
|
||||
0.9.0c -- changed setting of nGroups in sendMTFValues()
|
||||
so as to do a bit better on small files
|
||||
*/
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- Bit stream I/O ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_bsInitWrite ( EState* s )
|
||||
{
|
||||
s->bsLive = 0;
|
||||
s->bsBuff = 0;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsFinishWrite ( EState* s )
|
||||
{
|
||||
while (s->bsLive > 0) {
|
||||
s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
|
||||
s->numZ++;
|
||||
s->bsBuff <<= 8;
|
||||
s->bsLive -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define bsNEEDW(nz) \
|
||||
{ \
|
||||
while (s->bsLive >= 8) { \
|
||||
s->zbits[s->numZ] \
|
||||
= (UChar)(s->bsBuff >> 24); \
|
||||
s->numZ++; \
|
||||
s->bsBuff <<= 8; \
|
||||
s->bsLive -= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
__inline__
|
||||
void bsW ( EState* s, Int32 n, UInt32 v )
|
||||
{
|
||||
bsNEEDW ( n );
|
||||
s->bsBuff |= (v << (32 - s->bsLive - n));
|
||||
s->bsLive += n;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutUInt32 ( EState* s, UInt32 u )
|
||||
{
|
||||
bsW ( s, 8, (u >> 24) & 0xffL );
|
||||
bsW ( s, 8, (u >> 16) & 0xffL );
|
||||
bsW ( s, 8, (u >> 8) & 0xffL );
|
||||
bsW ( s, 8, u & 0xffL );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void bsPutUChar ( EState* s, UChar c )
|
||||
{
|
||||
bsW( s, 8, (UInt32)c );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/*--- The back end proper ---*/
|
||||
/*---------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_e ( EState* s )
|
||||
{
|
||||
Int32 i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (s->inUse[i]) {
|
||||
s->unseqToSeq[i] = s->nInUse;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void generateMTFValues ( EState* s )
|
||||
{
|
||||
UChar yy[256];
|
||||
Int32 i, j;
|
||||
Int32 zPend;
|
||||
Int32 wr;
|
||||
Int32 EOB;
|
||||
|
||||
/*
|
||||
After sorting (eg, here),
|
||||
s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
|
||||
and
|
||||
((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
|
||||
holds the original block data.
|
||||
|
||||
The first thing to do is generate the MTF values,
|
||||
and put them in
|
||||
((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
|
||||
Because there are strictly fewer or equal MTF values
|
||||
than block values, ptr values in this area are overwritten
|
||||
with MTF values only when they are no longer needed.
|
||||
|
||||
The final compressed bitstream is generated into the
|
||||
area starting at
|
||||
(UChar*) (&((UChar*)s->arr2)[s->nblock])
|
||||
|
||||
These storage aliases are set up in bzCompressInit(),
|
||||
except for the last one, which is arranged in
|
||||
compressBlock().
|
||||
*/
|
||||
UInt32* ptr = s->ptr;
|
||||
UChar* block = s->block;
|
||||
UInt16* mtfv = s->mtfv;
|
||||
|
||||
makeMaps_e ( s );
|
||||
EOB = s->nInUse+1;
|
||||
|
||||
for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
|
||||
|
||||
wr = 0;
|
||||
zPend = 0;
|
||||
for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
|
||||
|
||||
for (i = 0; i < s->nblock; i++) {
|
||||
UChar ll_i;
|
||||
AssertD ( wr <= i, "generateMTFValues(1)" );
|
||||
j = ptr[i]-1; if (j < 0) j += s->nblock;
|
||||
ll_i = s->unseqToSeq[block[j]];
|
||||
AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
|
||||
|
||||
if (yy[0] == ll_i) {
|
||||
zPend++;
|
||||
} else {
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (True) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (zPend - 2) / 2;
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
{
|
||||
register UChar rtmp;
|
||||
register UChar* ryy_j;
|
||||
register UChar rll_i;
|
||||
rtmp = yy[1];
|
||||
yy[1] = yy[0];
|
||||
ryy_j = &(yy[1]);
|
||||
rll_i = ll_i;
|
||||
while ( rll_i != rtmp ) {
|
||||
register UChar rtmp2;
|
||||
ryy_j++;
|
||||
rtmp2 = rtmp;
|
||||
rtmp = *ryy_j;
|
||||
*ryy_j = rtmp2;
|
||||
};
|
||||
yy[0] = rtmp;
|
||||
j = ryy_j - &(yy[0]);
|
||||
mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (zPend > 0) {
|
||||
zPend--;
|
||||
while (True) {
|
||||
if (zPend & 1) {
|
||||
mtfv[wr] = BZ_RUNB; wr++;
|
||||
s->mtfFreq[BZ_RUNB]++;
|
||||
} else {
|
||||
mtfv[wr] = BZ_RUNA; wr++;
|
||||
s->mtfFreq[BZ_RUNA]++;
|
||||
}
|
||||
if (zPend < 2) break;
|
||||
zPend = (zPend - 2) / 2;
|
||||
};
|
||||
zPend = 0;
|
||||
}
|
||||
|
||||
mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
|
||||
|
||||
s->nMTF = wr;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define BZ_LESSER_ICOST 0
|
||||
#define BZ_GREATER_ICOST 15
|
||||
|
||||
static
|
||||
void sendMTFValues ( EState* s )
|
||||
{
|
||||
Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
|
||||
Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
|
||||
Int32 nGroups, nBytes;
|
||||
|
||||
/*--
|
||||
UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
is a global since the decoder also needs it.
|
||||
|
||||
Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
|
||||
are also globals only used in this proc.
|
||||
Made global to keep stack frame size small.
|
||||
--*/
|
||||
|
||||
|
||||
UInt16 cost[BZ_N_GROUPS];
|
||||
Int32 fave[BZ_N_GROUPS];
|
||||
|
||||
UInt16* mtfv = s->mtfv;
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
|
||||
"%d+2 syms in use\n",
|
||||
s->nblock, s->nMTF, s->nInUse );
|
||||
|
||||
alphaSize = s->nInUse+2;
|
||||
for (t = 0; t < BZ_N_GROUPS; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->len[t][v] = BZ_GREATER_ICOST;
|
||||
|
||||
/*--- Decide how many coding tables to use ---*/
|
||||
AssertH ( s->nMTF > 0, 3001 );
|
||||
if (s->nMTF < 200) nGroups = 2; else
|
||||
if (s->nMTF < 600) nGroups = 3; else
|
||||
if (s->nMTF < 1200) nGroups = 4; else
|
||||
if (s->nMTF < 2400) nGroups = 5; else
|
||||
nGroups = 6;
|
||||
|
||||
/*--- Generate an initial set of coding tables ---*/
|
||||
{
|
||||
Int32 nPart, remF, tFreq, aFreq;
|
||||
|
||||
nPart = nGroups;
|
||||
remF = s->nMTF;
|
||||
gs = 0;
|
||||
while (nPart > 0) {
|
||||
tFreq = remF / nPart;
|
||||
ge = gs-1;
|
||||
aFreq = 0;
|
||||
while (aFreq < tFreq && ge < alphaSize-1) {
|
||||
ge++;
|
||||
aFreq += s->mtfFreq[ge];
|
||||
}
|
||||
|
||||
if (ge > gs
|
||||
&& nPart != nGroups && nPart != 1
|
||||
&& ((nGroups-nPart) % 2 == 1)) {
|
||||
aFreq -= s->mtfFreq[ge];
|
||||
ge--;
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf5( " initial group %d, [%d .. %d], "
|
||||
"has %d syms (%4.1f%%)\n",
|
||||
nPart, gs, ge, aFreq,
|
||||
(100.0 * (float)aFreq) / (float)(s->nMTF) );
|
||||
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
if (v >= gs && v <= ge)
|
||||
s->len[nPart-1][v] = BZ_LESSER_ICOST; else
|
||||
s->len[nPart-1][v] = BZ_GREATER_ICOST;
|
||||
|
||||
nPart--;
|
||||
gs = ge+1;
|
||||
remF -= aFreq;
|
||||
}
|
||||
}
|
||||
|
||||
/*---
|
||||
Iterate up to BZ_N_ITERS times to improve the tables.
|
||||
---*/
|
||||
for (iter = 0; iter < BZ_N_ITERS; iter++) {
|
||||
|
||||
for (t = 0; t < nGroups; t++) fave[t] = 0;
|
||||
|
||||
for (t = 0; t < nGroups; t++)
|
||||
for (v = 0; v < alphaSize; v++)
|
||||
s->rfreq[t][v] = 0;
|
||||
|
||||
/*---
|
||||
Set up an auxiliary length table which is used to fast-track
|
||||
the common case (nGroups == 6).
|
||||
---*/
|
||||
if (nGroups == 6) {
|
||||
for (v = 0; v < alphaSize; v++) {
|
||||
s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
|
||||
s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
|
||||
s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
|
||||
}
|
||||
}
|
||||
|
||||
nSelectors = 0;
|
||||
totc = 0;
|
||||
gs = 0;
|
||||
while (True) {
|
||||
|
||||
/*--- Set group start & end marks. --*/
|
||||
if (gs >= s->nMTF) break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF) ge = s->nMTF-1;
|
||||
|
||||
/*--
|
||||
Calculate the cost of this group as coded
|
||||
by each of the coding tables.
|
||||
--*/
|
||||
for (t = 0; t < nGroups; t++) cost[t] = 0;
|
||||
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
register UInt32 cost01, cost23, cost45;
|
||||
register UInt16 icv;
|
||||
cost01 = cost23 = cost45 = 0;
|
||||
|
||||
# define BZ_ITER(nn) \
|
||||
icv = mtfv[gs+(nn)]; \
|
||||
cost01 += s->len_pack[icv][0]; \
|
||||
cost23 += s->len_pack[icv][1]; \
|
||||
cost45 += s->len_pack[icv][2]; \
|
||||
|
||||
BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
|
||||
BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
|
||||
BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
|
||||
BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
|
||||
BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
|
||||
BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
|
||||
BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
|
||||
BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
|
||||
BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
|
||||
BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
|
||||
|
||||
# undef BZ_ITER
|
||||
|
||||
cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
|
||||
cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
|
||||
cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
UInt16 icv = mtfv[i];
|
||||
for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
|
||||
}
|
||||
}
|
||||
|
||||
/*--
|
||||
Find the coding table which is best for this group,
|
||||
and record its identity in the selector table.
|
||||
--*/
|
||||
bc = 999999999; bt = -1;
|
||||
for (t = 0; t < nGroups; t++)
|
||||
if (cost[t] < bc) { bc = cost[t]; bt = t; };
|
||||
totc += bc;
|
||||
fave[bt]++;
|
||||
s->selector[nSelectors] = bt;
|
||||
nSelectors++;
|
||||
|
||||
/*--
|
||||
Increment the symbol frequencies for the selected table.
|
||||
--*/
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
|
||||
# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
|
||||
|
||||
BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
|
||||
BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
|
||||
BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
|
||||
BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
|
||||
BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
|
||||
BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
|
||||
BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
|
||||
BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
|
||||
BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
|
||||
BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
|
||||
|
||||
# undef BZ_ITUR
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++)
|
||||
s->rfreq[bt][ mtfv[i] ]++;
|
||||
}
|
||||
|
||||
gs = ge+1;
|
||||
}
|
||||
if (s->verbosity >= 3) {
|
||||
VPrintf2 ( " pass %d: size is %d, grp uses are ",
|
||||
iter+1, totc/8 );
|
||||
for (t = 0; t < nGroups; t++)
|
||||
VPrintf1 ( "%d ", fave[t] );
|
||||
VPrintf0 ( "\n" );
|
||||
}
|
||||
|
||||
/*--
|
||||
Recompute the tables based on the accumulated frequencies.
|
||||
--*/
|
||||
/* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
|
||||
comment in huffman.c for details. */
|
||||
for (t = 0; t < nGroups; t++)
|
||||
BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
|
||||
alphaSize, 17 /*20*/ );
|
||||
}
|
||||
|
||||
|
||||
AssertH( nGroups < 8, 3002 );
|
||||
AssertH( nSelectors < 32768 &&
|
||||
nSelectors <= (2 + (900000 / BZ_G_SIZE)),
|
||||
3003 );
|
||||
|
||||
|
||||
/*--- Compute MTF values for the selectors. ---*/
|
||||
{
|
||||
UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
|
||||
for (i = 0; i < nGroups; i++) pos[i] = i;
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
ll_i = s->selector[i];
|
||||
j = 0;
|
||||
tmp = pos[j];
|
||||
while ( ll_i != tmp ) {
|
||||
j++;
|
||||
tmp2 = tmp;
|
||||
tmp = pos[j];
|
||||
pos[j] = tmp2;
|
||||
};
|
||||
pos[0] = tmp;
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
};
|
||||
|
||||
/*--- Assign actual codes for the tables. --*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
|
||||
AssertH ( !(minLen < 1), 3005 );
|
||||
BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
|
||||
minLen, maxLen, alphaSize );
|
||||
}
|
||||
|
||||
/*--- Transmit the mapping table. ---*/
|
||||
{
|
||||
Bool inUse16[16];
|
||||
for (i = 0; i < 16; i++) {
|
||||
inUse16[i] = False;
|
||||
for (j = 0; j < 16; j++)
|
||||
if (s->inUse[i * 16 + j]) inUse16[i] = True;
|
||||
}
|
||||
|
||||
nBytes = s->numZ;
|
||||
for (i = 0; i < 16; i++)
|
||||
if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (inUse16[i])
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
|
||||
}
|
||||
|
||||
/*--- Now the selectors. ---*/
|
||||
nBytes = s->numZ;
|
||||
bsW ( s, 3, nGroups );
|
||||
bsW ( s, 15, nSelectors );
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
|
||||
bsW(s,1,0);
|
||||
}
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( "selectors %d, ", s->numZ-nBytes );
|
||||
|
||||
/*--- Now the coding tables. ---*/
|
||||
nBytes = s->numZ;
|
||||
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
Int32 curr = s->len[t][0];
|
||||
bsW ( s, 5, curr );
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
|
||||
while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
|
||||
bsW ( s, 1, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
|
||||
|
||||
/*--- And finally, the block data proper ---*/
|
||||
nBytes = s->numZ;
|
||||
selCtr = 0;
|
||||
gs = 0;
|
||||
while (True) {
|
||||
if (gs >= s->nMTF) break;
|
||||
ge = gs + BZ_G_SIZE - 1;
|
||||
if (ge >= s->nMTF) ge = s->nMTF-1;
|
||||
AssertH ( s->selector[selCtr] < nGroups, 3006 );
|
||||
|
||||
if (nGroups == 6 && 50 == ge-gs+1) {
|
||||
/*--- fast track the common case ---*/
|
||||
UInt16 mtfv_i;
|
||||
UChar* s_len_sel_selCtr
|
||||
= &(s->len[s->selector[selCtr]][0]);
|
||||
Int32* s_code_sel_selCtr
|
||||
= &(s->code[s->selector[selCtr]][0]);
|
||||
|
||||
# define BZ_ITAH(nn) \
|
||||
mtfv_i = mtfv[gs+(nn)]; \
|
||||
bsW ( s, \
|
||||
s_len_sel_selCtr[mtfv_i], \
|
||||
s_code_sel_selCtr[mtfv_i] )
|
||||
|
||||
BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
|
||||
BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
|
||||
BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
|
||||
BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
|
||||
BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
|
||||
BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
|
||||
BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
|
||||
BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
|
||||
BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
|
||||
BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
|
||||
|
||||
# undef BZ_ITAH
|
||||
|
||||
} else {
|
||||
/*--- slow version which correctly handles all situations ---*/
|
||||
for (i = gs; i <= ge; i++) {
|
||||
bsW ( s,
|
||||
s->len [s->selector[selCtr]] [mtfv[i]],
|
||||
s->code [s->selector[selCtr]] [mtfv[i]] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gs = ge+1;
|
||||
selCtr++;
|
||||
}
|
||||
AssertH( selCtr == nSelectors, 3007 );
|
||||
|
||||
if (s->verbosity >= 3)
|
||||
VPrintf1( "codes %d\n", s->numZ-nBytes );
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_compressBlock ( EState* s, Bool is_last_block )
|
||||
{
|
||||
if (s->nblock > 0) {
|
||||
|
||||
BZ_FINALISE_CRC ( s->blockCRC );
|
||||
s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
|
||||
s->combinedCRC ^= s->blockCRC;
|
||||
if (s->blockNo > 1) s->numZ = 0;
|
||||
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf4( " block %d: crc = 0x%08x, "
|
||||
"combined CRC = 0x%08x, size = %d\n",
|
||||
s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
|
||||
|
||||
BZ2_blockSort ( s );
|
||||
}
|
||||
|
||||
s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
|
||||
|
||||
/*-- If this is the first block, create the stream header. --*/
|
||||
if (s->blockNo == 1) {
|
||||
BZ2_bsInitWrite ( s );
|
||||
bsPutUChar ( s, BZ_HDR_B );
|
||||
bsPutUChar ( s, BZ_HDR_Z );
|
||||
bsPutUChar ( s, BZ_HDR_h );
|
||||
bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
|
||||
}
|
||||
|
||||
if (s->nblock > 0) {
|
||||
|
||||
bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
|
||||
bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
|
||||
bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
|
||||
|
||||
/*-- Now the block's CRC, so it is in a known place. --*/
|
||||
bsPutUInt32 ( s, s->blockCRC );
|
||||
|
||||
/*--
|
||||
Now a single bit indicating (non-)randomisation.
|
||||
As of version 0.9.5, we use a better sorting algorithm
|
||||
which makes randomisation unnecessary. So always set
|
||||
the randomised bit to 'no'. Of course, the decoder
|
||||
still needs to be able to handle randomised blocks
|
||||
so as to maintain backwards compatibility with
|
||||
older versions of bzip2.
|
||||
--*/
|
||||
bsW(s,1,0);
|
||||
|
||||
bsW ( s, 24, s->origPtr );
|
||||
generateMTFValues ( s );
|
||||
sendMTFValues ( s );
|
||||
}
|
||||
|
||||
|
||||
/*-- If this is the last block, add the stream trailer. --*/
|
||||
if (is_last_block) {
|
||||
|
||||
bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
|
||||
bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
|
||||
bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
|
||||
bsPutUInt32 ( s, s->combinedCRC );
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
|
||||
bsFinishWrite ( s );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end compress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
104
patchlib/crctable.c
Normal file
104
patchlib/crctable.c
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Table for doing CRCs ---*/
|
||||
/*--- crctable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
/*--
|
||||
I think this is an implementation of the AUTODIN-II,
|
||||
Ethernet & FDDI 32-bit CRC standard. Vaguely derived
|
||||
from code by Rob Warnock, in Section 51 of the
|
||||
comp.compression FAQ.
|
||||
--*/
|
||||
|
||||
UInt32 BZ2_crc32Table[256] = {
|
||||
|
||||
/*-- Ugly, innit? --*/
|
||||
|
||||
0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
|
||||
0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
|
||||
0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
|
||||
0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
|
||||
0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
|
||||
0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
|
||||
0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
|
||||
0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
|
||||
0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
|
||||
0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
|
||||
0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
|
||||
0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
|
||||
0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
|
||||
0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
|
||||
0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
|
||||
0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
|
||||
0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
|
||||
0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
|
||||
0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
|
||||
0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
|
||||
0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
|
||||
0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
|
||||
0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
|
||||
0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
|
||||
0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
|
||||
0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
|
||||
0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
|
||||
0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
|
||||
0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
|
||||
0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
|
||||
0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
|
||||
0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
|
||||
0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
|
||||
0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
|
||||
0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
|
||||
0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
|
||||
0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
|
||||
0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
|
||||
0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
|
||||
0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
|
||||
0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
|
||||
0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
|
||||
0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
|
||||
0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
|
||||
0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
|
||||
0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
|
||||
0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
|
||||
0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
|
||||
0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
|
||||
0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
|
||||
0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
|
||||
0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
|
||||
0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
|
||||
0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
|
||||
0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
|
||||
0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
|
||||
0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
|
||||
0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
|
||||
0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
|
||||
0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
|
||||
0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
|
||||
0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
|
||||
0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
|
||||
0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end crctable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
646
patchlib/decompress.c
Normal file
646
patchlib/decompress.c
Normal file
@ -0,0 +1,646 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Decompression machinery ---*/
|
||||
/*--- decompress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
static
|
||||
void makeMaps_d ( DState* s )
|
||||
{
|
||||
Int32 i;
|
||||
s->nInUse = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (s->inUse[i]) {
|
||||
s->seqToUnseq[s->nInUse] = i;
|
||||
s->nInUse++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define RETURN(rrr) \
|
||||
{ retVal = rrr; goto save_state_and_return; };
|
||||
|
||||
#define GET_BITS(lll,vvv,nnn) \
|
||||
case lll: s->state = lll; \
|
||||
while (True) { \
|
||||
if (s->bsLive >= nnn) { \
|
||||
UInt32 v; \
|
||||
v = (s->bsBuff >> \
|
||||
(s->bsLive-nnn)) & ((1 << nnn)-1); \
|
||||
s->bsLive -= nnn; \
|
||||
vvv = v; \
|
||||
break; \
|
||||
} \
|
||||
if (s->strm->avail_in == 0) RETURN(BZ_OK); \
|
||||
s->bsBuff \
|
||||
= (s->bsBuff << 8) | \
|
||||
((UInt32) \
|
||||
(*((UChar*)(s->strm->next_in)))); \
|
||||
s->bsLive += 8; \
|
||||
s->strm->next_in++; \
|
||||
s->strm->avail_in--; \
|
||||
s->strm->total_in_lo32++; \
|
||||
if (s->strm->total_in_lo32 == 0) \
|
||||
s->strm->total_in_hi32++; \
|
||||
}
|
||||
|
||||
#define GET_UCHAR(lll,uuu) \
|
||||
GET_BITS(lll,uuu,8)
|
||||
|
||||
#define GET_BIT(lll,uuu) \
|
||||
GET_BITS(lll,uuu,1)
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define GET_MTF_VAL(label1,label2,lval) \
|
||||
{ \
|
||||
if (groupPos == 0) { \
|
||||
groupNo++; \
|
||||
if (groupNo >= nSelectors) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
groupPos = BZ_G_SIZE; \
|
||||
gSel = s->selector[groupNo]; \
|
||||
gMinlen = s->minLens[gSel]; \
|
||||
gLimit = &(s->limit[gSel][0]); \
|
||||
gPerm = &(s->perm[gSel][0]); \
|
||||
gBase = &(s->base[gSel][0]); \
|
||||
} \
|
||||
groupPos--; \
|
||||
zn = gMinlen; \
|
||||
GET_BITS(label1, zvec, zn); \
|
||||
while (1) { \
|
||||
if (zn > 20 /* the longest code */) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
if (zvec <= gLimit[zn]) break; \
|
||||
zn++; \
|
||||
GET_BIT(label2, zj); \
|
||||
zvec = (zvec << 1) | zj; \
|
||||
}; \
|
||||
if (zvec - gBase[zn] < 0 \
|
||||
|| zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
|
||||
RETURN(BZ_DATA_ERROR); \
|
||||
lval = gPerm[zvec - gBase[zn]]; \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
Int32 BZ2_decompress ( DState* s )
|
||||
{
|
||||
UChar uc;
|
||||
Int32 retVal;
|
||||
Int32 minLen, maxLen;
|
||||
bz_stream* strm = s->strm;
|
||||
|
||||
/* stuff that needs to be saved/restored */
|
||||
Int32 i;
|
||||
Int32 j;
|
||||
Int32 t;
|
||||
Int32 alphaSize;
|
||||
Int32 nGroups;
|
||||
Int32 nSelectors;
|
||||
Int32 EOB;
|
||||
Int32 groupNo;
|
||||
Int32 groupPos;
|
||||
Int32 nextSym;
|
||||
Int32 nblockMAX;
|
||||
Int32 nblock;
|
||||
Int32 es;
|
||||
Int32 N;
|
||||
Int32 curr;
|
||||
Int32 zt;
|
||||
Int32 zn;
|
||||
Int32 zvec;
|
||||
Int32 zj;
|
||||
Int32 gSel;
|
||||
Int32 gMinlen;
|
||||
Int32* gLimit;
|
||||
Int32* gBase;
|
||||
Int32* gPerm;
|
||||
|
||||
if (s->state == BZ_X_MAGIC_1) {
|
||||
/*initialise the save area*/
|
||||
s->save_i = 0;
|
||||
s->save_j = 0;
|
||||
s->save_t = 0;
|
||||
s->save_alphaSize = 0;
|
||||
s->save_nGroups = 0;
|
||||
s->save_nSelectors = 0;
|
||||
s->save_EOB = 0;
|
||||
s->save_groupNo = 0;
|
||||
s->save_groupPos = 0;
|
||||
s->save_nextSym = 0;
|
||||
s->save_nblockMAX = 0;
|
||||
s->save_nblock = 0;
|
||||
s->save_es = 0;
|
||||
s->save_N = 0;
|
||||
s->save_curr = 0;
|
||||
s->save_zt = 0;
|
||||
s->save_zn = 0;
|
||||
s->save_zvec = 0;
|
||||
s->save_zj = 0;
|
||||
s->save_gSel = 0;
|
||||
s->save_gMinlen = 0;
|
||||
s->save_gLimit = NULL;
|
||||
s->save_gBase = NULL;
|
||||
s->save_gPerm = NULL;
|
||||
}
|
||||
|
||||
/*restore from the save area*/
|
||||
i = s->save_i;
|
||||
j = s->save_j;
|
||||
t = s->save_t;
|
||||
alphaSize = s->save_alphaSize;
|
||||
nGroups = s->save_nGroups;
|
||||
nSelectors = s->save_nSelectors;
|
||||
EOB = s->save_EOB;
|
||||
groupNo = s->save_groupNo;
|
||||
groupPos = s->save_groupPos;
|
||||
nextSym = s->save_nextSym;
|
||||
nblockMAX = s->save_nblockMAX;
|
||||
nblock = s->save_nblock;
|
||||
es = s->save_es;
|
||||
N = s->save_N;
|
||||
curr = s->save_curr;
|
||||
zt = s->save_zt;
|
||||
zn = s->save_zn;
|
||||
zvec = s->save_zvec;
|
||||
zj = s->save_zj;
|
||||
gSel = s->save_gSel;
|
||||
gMinlen = s->save_gMinlen;
|
||||
gLimit = s->save_gLimit;
|
||||
gBase = s->save_gBase;
|
||||
gPerm = s->save_gPerm;
|
||||
|
||||
retVal = BZ_OK;
|
||||
|
||||
switch (s->state) {
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_1, uc);
|
||||
if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_2, uc);
|
||||
if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_UCHAR(BZ_X_MAGIC_3, uc)
|
||||
if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
|
||||
GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
|
||||
if (s->blockSize100k < (BZ_HDR_0 + 1) ||
|
||||
s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
|
||||
s->blockSize100k -= BZ_HDR_0;
|
||||
|
||||
if (s->smallDecompress) {
|
||||
s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
|
||||
s->ll4 = BZALLOC(
|
||||
((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
|
||||
);
|
||||
if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
|
||||
} else {
|
||||
s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
|
||||
if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
|
||||
}
|
||||
|
||||
GET_UCHAR(BZ_X_BLKHDR_1, uc);
|
||||
|
||||
if (uc == 0x17) goto endhdr_2;
|
||||
if (uc != 0x31) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_2, uc);
|
||||
if (uc != 0x41) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_3, uc);
|
||||
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_4, uc);
|
||||
if (uc != 0x26) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_5, uc);
|
||||
if (uc != 0x53) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_BLKHDR_6, uc);
|
||||
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
s->currBlockNo++;
|
||||
if (s->verbosity >= 2)
|
||||
VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
|
||||
|
||||
s->storedBlockCRC = 0;
|
||||
GET_UCHAR(BZ_X_BCRC_1, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_2, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_3, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_BCRC_4, uc);
|
||||
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
|
||||
|
||||
GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
|
||||
|
||||
s->origPtr = 0;
|
||||
GET_UCHAR(BZ_X_ORIGPTR_1, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
GET_UCHAR(BZ_X_ORIGPTR_2, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
GET_UCHAR(BZ_X_ORIGPTR_3, uc);
|
||||
s->origPtr = (s->origPtr << 8) | ((Int32)uc);
|
||||
|
||||
if (s->origPtr < 0)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
if (s->origPtr > 10 + 100000*s->blockSize100k)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*--- Receive the mapping table ---*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
GET_BIT(BZ_X_MAPPING_1, uc);
|
||||
if (uc == 1)
|
||||
s->inUse16[i] = True; else
|
||||
s->inUse16[i] = False;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) s->inUse[i] = False;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (s->inUse16[i])
|
||||
for (j = 0; j < 16; j++) {
|
||||
GET_BIT(BZ_X_MAPPING_2, uc);
|
||||
if (uc == 1) s->inUse[i * 16 + j] = True;
|
||||
}
|
||||
makeMaps_d ( s );
|
||||
if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
|
||||
alphaSize = s->nInUse+2;
|
||||
|
||||
/*--- Now the selectors ---*/
|
||||
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
|
||||
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
|
||||
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
|
||||
if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
j = 0;
|
||||
while (True) {
|
||||
GET_BIT(BZ_X_SELECTOR_3, uc);
|
||||
if (uc == 0) break;
|
||||
j++;
|
||||
if (j >= nGroups) RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
s->selectorMtf[i] = j;
|
||||
}
|
||||
|
||||
/*--- Undo the MTF values for the selectors. ---*/
|
||||
{
|
||||
UChar pos[BZ_N_GROUPS], tmp, v;
|
||||
for (v = 0; v < nGroups; v++) pos[v] = v;
|
||||
|
||||
for (i = 0; i < nSelectors; i++) {
|
||||
v = s->selectorMtf[i];
|
||||
tmp = pos[v];
|
||||
while (v > 0) { pos[v] = pos[v-1]; v--; }
|
||||
pos[0] = tmp;
|
||||
s->selector[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Now the coding tables ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
GET_BITS(BZ_X_CODING_1, curr, 5);
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
while (True) {
|
||||
if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
|
||||
GET_BIT(BZ_X_CODING_2, uc);
|
||||
if (uc == 0) break;
|
||||
GET_BIT(BZ_X_CODING_3, uc);
|
||||
if (uc == 0) curr++; else curr--;
|
||||
}
|
||||
s->len[t][i] = curr;
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Create the Huffman decoding tables ---*/
|
||||
for (t = 0; t < nGroups; t++) {
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++) {
|
||||
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
|
||||
if (s->len[t][i] < minLen) minLen = s->len[t][i];
|
||||
}
|
||||
BZ2_hbCreateDecodeTables (
|
||||
&(s->limit[t][0]),
|
||||
&(s->base[t][0]),
|
||||
&(s->perm[t][0]),
|
||||
&(s->len[t][0]),
|
||||
minLen, maxLen, alphaSize
|
||||
);
|
||||
s->minLens[t] = minLen;
|
||||
}
|
||||
|
||||
/*--- Now the MTF values ---*/
|
||||
|
||||
EOB = s->nInUse+1;
|
||||
nblockMAX = 100000 * s->blockSize100k;
|
||||
groupNo = -1;
|
||||
groupPos = 0;
|
||||
|
||||
for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
|
||||
|
||||
/*-- MTF init --*/
|
||||
{
|
||||
Int32 ii, jj, kk;
|
||||
kk = MTFA_SIZE-1;
|
||||
for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
|
||||
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
|
||||
s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
|
||||
kk--;
|
||||
}
|
||||
s->mtfbase[ii] = kk + 1;
|
||||
}
|
||||
}
|
||||
/*-- end MTF init --*/
|
||||
|
||||
nblock = 0;
|
||||
GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
|
||||
|
||||
while (True) {
|
||||
|
||||
if (nextSym == EOB) break;
|
||||
|
||||
if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
|
||||
|
||||
es = -1;
|
||||
N = 1;
|
||||
do {
|
||||
/* Check that N doesn't get too big, so that es doesn't
|
||||
go negative. The maximum value that can be
|
||||
RUNA/RUNB encoded is equal to the block size (post
|
||||
the initial RLE), viz, 900k, so bounding N at 2
|
||||
million should guard against overflow without
|
||||
rejecting any legitimate inputs. */
|
||||
if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
|
||||
if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
|
||||
if (nextSym == BZ_RUNB) es = es + (1+1) * N;
|
||||
N = N * 2;
|
||||
GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
|
||||
}
|
||||
while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
|
||||
|
||||
es++;
|
||||
uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
|
||||
s->unzftab[uc] += es;
|
||||
|
||||
if (s->smallDecompress)
|
||||
while (es > 0) {
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
s->ll16[nblock] = (UInt16)uc;
|
||||
nblock++;
|
||||
es--;
|
||||
}
|
||||
else
|
||||
while (es > 0) {
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
s->tt[nblock] = (UInt32)uc;
|
||||
nblock++;
|
||||
es--;
|
||||
};
|
||||
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*-- uc = MTF ( nextSym-1 ) --*/
|
||||
{
|
||||
Int32 ii, jj, kk, pp, lno, off;
|
||||
UInt32 nn;
|
||||
nn = (UInt32)(nextSym - 1);
|
||||
|
||||
if (nn < MTFL_SIZE) {
|
||||
/* avoid general-case expense */
|
||||
pp = s->mtfbase[0];
|
||||
uc = s->mtfa[pp+nn];
|
||||
while (nn > 3) {
|
||||
Int32 z = pp+nn;
|
||||
s->mtfa[(z) ] = s->mtfa[(z)-1];
|
||||
s->mtfa[(z)-1] = s->mtfa[(z)-2];
|
||||
s->mtfa[(z)-2] = s->mtfa[(z)-3];
|
||||
s->mtfa[(z)-3] = s->mtfa[(z)-4];
|
||||
nn -= 4;
|
||||
}
|
||||
while (nn > 0) {
|
||||
s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
|
||||
};
|
||||
s->mtfa[pp] = uc;
|
||||
} else {
|
||||
/* general case */
|
||||
lno = nn / MTFL_SIZE;
|
||||
off = nn % MTFL_SIZE;
|
||||
pp = s->mtfbase[lno] + off;
|
||||
uc = s->mtfa[pp];
|
||||
while (pp > s->mtfbase[lno]) {
|
||||
s->mtfa[pp] = s->mtfa[pp-1]; pp--;
|
||||
};
|
||||
s->mtfbase[lno]++;
|
||||
while (lno > 0) {
|
||||
s->mtfbase[lno]--;
|
||||
s->mtfa[s->mtfbase[lno]]
|
||||
= s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
|
||||
lno--;
|
||||
}
|
||||
s->mtfbase[0]--;
|
||||
s->mtfa[s->mtfbase[0]] = uc;
|
||||
if (s->mtfbase[0] == 0) {
|
||||
kk = MTFA_SIZE-1;
|
||||
for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
|
||||
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
|
||||
s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
|
||||
kk--;
|
||||
}
|
||||
s->mtfbase[ii] = kk + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-- end uc = MTF ( nextSym-1 ) --*/
|
||||
|
||||
s->unzftab[s->seqToUnseq[uc]]++;
|
||||
if (s->smallDecompress)
|
||||
s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
|
||||
s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
|
||||
nblock++;
|
||||
|
||||
GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know what nblock is, we can do a better sanity
|
||||
check on s->origPtr.
|
||||
*/
|
||||
if (s->origPtr < 0 || s->origPtr >= nblock)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
|
||||
/*-- Set up cftab to facilitate generation of T^(-1) --*/
|
||||
/* Check: unzftab entries in range. */
|
||||
for (i = 0; i <= 255; i++) {
|
||||
if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
/* Actually generate cftab. */
|
||||
s->cftab[0] = 0;
|
||||
for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
|
||||
for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
|
||||
/* Check: cftab entries in range. */
|
||||
for (i = 0; i <= 256; i++) {
|
||||
if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
|
||||
/* s->cftab[i] can legitimately be == nblock */
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
}
|
||||
/* Check: cftab entries non-descending. */
|
||||
for (i = 1; i <= 256; i++) {
|
||||
if (s->cftab[i-1] > s->cftab[i]) {
|
||||
RETURN(BZ_DATA_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
s->state_out_len = 0;
|
||||
s->state_out_ch = 0;
|
||||
BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
|
||||
s->state = BZ_X_OUTPUT;
|
||||
if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
|
||||
|
||||
if (s->smallDecompress) {
|
||||
|
||||
/*-- Make a copy of cftab, used in generation of T --*/
|
||||
for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
|
||||
|
||||
/*-- compute the T vector --*/
|
||||
for (i = 0; i < nblock; i++) {
|
||||
uc = (UChar)(s->ll16[i]);
|
||||
SET_LL(i, s->cftabCopy[uc]);
|
||||
s->cftabCopy[uc]++;
|
||||
}
|
||||
|
||||
/*-- Compute T^(-1) by pointer reversal on T --*/
|
||||
i = s->origPtr;
|
||||
j = GET_LL(i);
|
||||
do {
|
||||
Int32 tmp = GET_LL(j);
|
||||
SET_LL(j, i);
|
||||
i = j;
|
||||
j = tmp;
|
||||
}
|
||||
while (i != s->origPtr);
|
||||
|
||||
s->tPos = s->origPtr;
|
||||
s->nblock_used = 0;
|
||||
if (s->blockRandomised) {
|
||||
BZ_RAND_INIT_MASK;
|
||||
BZ_GET_SMALL(s->k0); s->nblock_used++;
|
||||
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
|
||||
} else {
|
||||
BZ_GET_SMALL(s->k0); s->nblock_used++;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*-- compute the T^(-1) vector --*/
|
||||
for (i = 0; i < nblock; i++) {
|
||||
uc = (UChar)(s->tt[i] & 0xff);
|
||||
s->tt[s->cftab[uc]] |= (i << 8);
|
||||
s->cftab[uc]++;
|
||||
}
|
||||
|
||||
s->tPos = s->tt[s->origPtr] >> 8;
|
||||
s->nblock_used = 0;
|
||||
if (s->blockRandomised) {
|
||||
BZ_RAND_INIT_MASK;
|
||||
BZ_GET_FAST(s->k0); s->nblock_used++;
|
||||
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
|
||||
} else {
|
||||
BZ_GET_FAST(s->k0); s->nblock_used++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RETURN(BZ_OK);
|
||||
|
||||
|
||||
|
||||
endhdr_2:
|
||||
|
||||
GET_UCHAR(BZ_X_ENDHDR_2, uc);
|
||||
if (uc != 0x72) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_3, uc);
|
||||
if (uc != 0x45) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_4, uc);
|
||||
if (uc != 0x38) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_5, uc);
|
||||
if (uc != 0x50) RETURN(BZ_DATA_ERROR);
|
||||
GET_UCHAR(BZ_X_ENDHDR_6, uc);
|
||||
if (uc != 0x90) RETURN(BZ_DATA_ERROR);
|
||||
|
||||
s->storedCombinedCRC = 0;
|
||||
GET_UCHAR(BZ_X_CCRC_1, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_2, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_3, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
GET_UCHAR(BZ_X_CCRC_4, uc);
|
||||
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
|
||||
|
||||
s->state = BZ_X_IDLE;
|
||||
RETURN(BZ_STREAM_END);
|
||||
|
||||
default: AssertH ( False, 4001 );
|
||||
}
|
||||
|
||||
AssertH ( False, 4002 );
|
||||
|
||||
save_state_and_return:
|
||||
|
||||
s->save_i = i;
|
||||
s->save_j = j;
|
||||
s->save_t = t;
|
||||
s->save_alphaSize = alphaSize;
|
||||
s->save_nGroups = nGroups;
|
||||
s->save_nSelectors = nSelectors;
|
||||
s->save_EOB = EOB;
|
||||
s->save_groupNo = groupNo;
|
||||
s->save_groupPos = groupPos;
|
||||
s->save_nextSym = nextSym;
|
||||
s->save_nblockMAX = nblockMAX;
|
||||
s->save_nblock = nblock;
|
||||
s->save_es = es;
|
||||
s->save_N = N;
|
||||
s->save_curr = curr;
|
||||
s->save_zt = zt;
|
||||
s->save_zn = zn;
|
||||
s->save_zvec = zvec;
|
||||
s->save_zj = zj;
|
||||
s->save_gSel = gSel;
|
||||
s->save_gMinlen = gMinlen;
|
||||
s->save_gLimit = gLimit;
|
||||
s->save_gBase = gBase;
|
||||
s->save_gPerm = gPerm;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end decompress.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
205
patchlib/huffman.c
Normal file
205
patchlib/huffman.c
Normal file
@ -0,0 +1,205 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Huffman coding low-level stuff ---*/
|
||||
/*--- huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
|
||||
#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
|
||||
#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
|
||||
|
||||
#define ADDWEIGHTS(zw1,zw2) \
|
||||
(WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
|
||||
(1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
|
||||
|
||||
#define UPHEAP(z) \
|
||||
{ \
|
||||
Int32 zz, tmp; \
|
||||
zz = z; tmp = heap[zz]; \
|
||||
while (weight[tmp] < weight[heap[zz >> 1]]) { \
|
||||
heap[zz] = heap[zz >> 1]; \
|
||||
zz >>= 1; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
#define DOWNHEAP(z) \
|
||||
{ \
|
||||
Int32 zz, yy, tmp; \
|
||||
zz = z; tmp = heap[zz]; \
|
||||
while (True) { \
|
||||
yy = zz << 1; \
|
||||
if (yy > nHeap) break; \
|
||||
if (yy < nHeap && \
|
||||
weight[heap[yy+1]] < weight[heap[yy]]) \
|
||||
yy++; \
|
||||
if (weight[tmp] < weight[heap[yy]]) break; \
|
||||
heap[zz] = heap[yy]; \
|
||||
zz = yy; \
|
||||
} \
|
||||
heap[zz] = tmp; \
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbMakeCodeLengths ( UChar *len,
|
||||
Int32 *freq,
|
||||
Int32 alphaSize,
|
||||
Int32 maxLen )
|
||||
{
|
||||
/*--
|
||||
Nodes and heap entries run from 1. Entry 0
|
||||
for both the heap and nodes is a sentinel.
|
||||
--*/
|
||||
Int32 nNodes, nHeap, n1, n2, i, j, k;
|
||||
Bool tooLong;
|
||||
|
||||
Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
|
||||
Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
|
||||
Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
|
||||
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
|
||||
|
||||
while (True) {
|
||||
|
||||
nNodes = alphaSize;
|
||||
nHeap = 0;
|
||||
|
||||
heap[0] = 0;
|
||||
weight[0] = 0;
|
||||
parent[0] = -2;
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
parent[i] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = i;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
|
||||
|
||||
while (nHeap > 1) {
|
||||
n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
|
||||
n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
|
||||
nNodes++;
|
||||
parent[n1] = parent[n2] = nNodes;
|
||||
weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
|
||||
parent[nNodes] = -1;
|
||||
nHeap++;
|
||||
heap[nHeap] = nNodes;
|
||||
UPHEAP(nHeap);
|
||||
}
|
||||
|
||||
AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
|
||||
|
||||
tooLong = False;
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = 0;
|
||||
k = i;
|
||||
while (parent[k] >= 0) { k = parent[k]; j++; }
|
||||
len[i-1] = j;
|
||||
if (j > maxLen) tooLong = True;
|
||||
}
|
||||
|
||||
if (! tooLong) break;
|
||||
|
||||
/* 17 Oct 04: keep-going condition for the following loop used
|
||||
to be 'i < alphaSize', which missed the last element,
|
||||
theoretically leading to the possibility of the compressor
|
||||
looping. However, this count-scaling step is only needed if
|
||||
one of the generated Huffman code words is longer than
|
||||
maxLen, which up to and including version 1.0.2 was 20 bits,
|
||||
which is extremely unlikely. In version 1.0.3 maxLen was
|
||||
changed to 17 bits, which has minimal effect on compression
|
||||
ratio, but does mean this scaling step is used from time to
|
||||
time, enough to verify that it works.
|
||||
|
||||
This means that bzip2-1.0.3 and later will only produce
|
||||
Huffman codes with a maximum length of 17 bits. However, in
|
||||
order to preserve backwards compatibility with bitstreams
|
||||
produced by versions pre-1.0.3, the decompressor must still
|
||||
handle lengths of up to 20. */
|
||||
|
||||
for (i = 1; i <= alphaSize; i++) {
|
||||
j = weight[i] >> 8;
|
||||
j = 1 + (j / 2);
|
||||
weight[i] = j << 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbAssignCodes ( Int32 *code,
|
||||
UChar *length,
|
||||
Int32 minLen,
|
||||
Int32 maxLen,
|
||||
Int32 alphaSize )
|
||||
{
|
||||
Int32 n, vec, i;
|
||||
|
||||
vec = 0;
|
||||
for (n = minLen; n <= maxLen; n++) {
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
if (length[i] == n) { code[i] = vec; vec++; };
|
||||
vec <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
void BZ2_hbCreateDecodeTables ( Int32 *limit,
|
||||
Int32 *base,
|
||||
Int32 *perm,
|
||||
UChar *length,
|
||||
Int32 minLen,
|
||||
Int32 maxLen,
|
||||
Int32 alphaSize )
|
||||
{
|
||||
Int32 pp, i, j, vec;
|
||||
|
||||
pp = 0;
|
||||
for (i = minLen; i <= maxLen; i++)
|
||||
for (j = 0; j < alphaSize; j++)
|
||||
if (length[j] == i) { perm[pp] = j; pp++; };
|
||||
|
||||
for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
|
||||
for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
|
||||
|
||||
for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
|
||||
|
||||
for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
|
||||
vec = 0;
|
||||
|
||||
for (i = minLen; i <= maxLen; i++) {
|
||||
vec += (base[i+1] - base[i]);
|
||||
limit[i] = vec-1;
|
||||
vec <<= 1;
|
||||
}
|
||||
for (i = minLen + 1; i <= maxLen; i++)
|
||||
base[i] = ((limit[i-1] + 1) << 1) - base[i];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end huffman.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
84
patchlib/randtable.c
Normal file
84
patchlib/randtable.c
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- Table for randomising repetitive blocks ---*/
|
||||
/*--- randtable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
This file is part of bzip2/libbzip2, a program and library for
|
||||
lossless, block-sorting data compression.
|
||||
|
||||
bzip2/libbzip2 version 1.0.6 of 6 September 2010
|
||||
Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
|
||||
|
||||
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||
README file.
|
||||
|
||||
This program is released under the terms of the license contained
|
||||
in the file LICENSE.
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "bzlib_private.h"
|
||||
|
||||
|
||||
/*---------------------------------------------*/
|
||||
Int32 BZ2_rNums[512] = {
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
/*--- end randtable.c ---*/
|
||||
/*-------------------------------------------------------------*/
|
26
quazip/CMakeLists.txt
Normal file
26
quazip/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
# set all include directories for in and out of source builds
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
# include with QT_USE selected library parts
|
||||
# INCLUDE(${QT_USE_FILE})
|
||||
|
||||
file(GLOB SRCS "*.c" "*.cpp")
|
||||
file(GLOB PUBLIC_HEADERS "*.h")
|
||||
|
||||
# Must be added to enable export macro
|
||||
ADD_DEFINITIONS(-DQUAZIP_BUILD)
|
||||
|
||||
#qt5_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS})
|
||||
#set(SRCS ${SRCS} ${MOC_SRCS})
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_library(quazip STATIC ${SRCS})
|
||||
target_link_libraries(quazip ${ZLIB_LIBRARIES})
|
||||
|
||||
#install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip)
|
||||
#install(TARGETS quazip LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION})
|
469
quazip/JlCompress.cpp
Normal file
469
quazip/JlCompress.cpp
Normal file
@ -0,0 +1,469 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Comprime il file fileName, nell'oggetto zip, con il nome fileDest.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * zip==NULL;
|
||||
* * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file;
|
||||
* * non e possibile aprire il file d'origine;
|
||||
* * non e possibile creare il file all'interno dell'oggetto zip;
|
||||
* * si e rilevato un errore nella copia dei dati;
|
||||
* * non e stato possibile chiudere il file all'interno dell'oggetto zip;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Comprime la cartella dir nel file fileCompressed, se recursive e true allora
|
||||
* comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato
|
||||
* togliendo il pat della cartella origDir al path della cartella dir.
|
||||
* Se la funzione fallisce restituisce false e cancella il file che si e tentato
|
||||
* di creare.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * zip==NULL;
|
||||
* * l'oggetto zip e stato aperto in una modalita non compatibile con l'aggiunta di file;
|
||||
* * la cartella dir non esiste;
|
||||
* * la compressione di una sotto cartella fallisce (1);
|
||||
* * la compressione di un file fallisce;
|
||||
* (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle
|
||||
* dunque gli errori di compressione di una sotto cartella sono gli stessi di questa
|
||||
* funzione.
|
||||
*/
|
||||
bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) {
|
||||
// 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;
|
||||
|
||||
// Se comprimo anche le sotto cartelle
|
||||
if (recursive) {
|
||||
// Per ogni sotto cartella
|
||||
QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot);
|
||||
Q_FOREACH (QFileInfo file, files) {
|
||||
// Comprimo la sotto cartella
|
||||
if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Per ogni file nella cartella
|
||||
QFileInfoList files = directory.entryInfoList(QDir::Files);
|
||||
QDir origDirectory(origDir);
|
||||
Q_FOREACH (QFileInfo file, files) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest.
|
||||
* Se la funzione fallisce restituisce false e cancella il file che si e tentato di estrarre.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * zip==NULL;
|
||||
* * l'oggetto zip e stato aperto in una modalita non compatibile con l'estrazione di file;
|
||||
* * non e possibile aprire il file all'interno dell'oggetto zip;
|
||||
* * non e possibile creare il file estratto;
|
||||
* * si e rilevato un errore nella copia dei dati (1);
|
||||
* * non e stato possibile chiudere il file all'interno dell'oggetto zip (1);
|
||||
*
|
||||
* (1): prima di uscire dalla funzione cancella il file estratto.
|
||||
*/
|
||||
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 (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QFileInfo(fileDest).isDir())
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rimuove i file il cui nome e specificato all'interno di listFile.
|
||||
* Restituisce true se tutti i file sono stati cancellati correttamente, attenzione
|
||||
* perche puo restituire false anche se alcuni file non esistevano e si e tentato
|
||||
* di cancellarli.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/**OK
|
||||
* Comprime il file fileName nel file fileCompressed.
|
||||
* Se la funzione fallisce restituisce false e cancella il file che si e tentato
|
||||
* di creare.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * la compressione del file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Comprime i file specificati in files nel file fileCompressed.
|
||||
* Se la funzione fallisce restituisce false e cancella il file che si e tentato
|
||||
* di creare.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * la compressione di un file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
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;
|
||||
Q_FOREACH (QString file, files) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Comprime la cartella dir nel file fileCompressed, se recursive e true allora
|
||||
* comprime anche le sotto cartelle.
|
||||
* Se la funzione fallisce restituisce false e cancella il file che si e tentato
|
||||
* di creare.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * la compressione di un file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) {
|
||||
// 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)) {
|
||||
QFile::remove(fileCompressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Chiudo il file zip
|
||||
zip.close();
|
||||
if(zip.getZipError()!=0) {
|
||||
QFile::remove(fileCompressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/**OK
|
||||
* Estrae il file fileName, contenuto nel file fileCompressed, con il nome fileDest.
|
||||
* Se fileDest = "" allora il file viene estratto con lo stesso nome con cui e
|
||||
* stato compresso.
|
||||
* Se la funzione fallisce cancella il file che si e tentato di estrarre.
|
||||
* Restituisce il nome assoluto del file estratto.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * l'estrazione del file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
QString JlCompress::extractFile(QString fileCompressed, QString fileName, QString fileDest) {
|
||||
// Apro lo zip
|
||||
QuaZip zip(fileCompressed);
|
||||
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();
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Estrae i file specificati in files, contenuti nel file fileCompressed, nella
|
||||
* cartella dir. La struttura a cartelle del file compresso viene rispettata.
|
||||
* Se dir = "" allora il file viene estratto nella cartella corrente.
|
||||
* Se la funzione fallisce cancella i file che si e tentato di estrarre.
|
||||
* Restituisce i nomi assoluti dei file estratti.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * l'estrazione di un file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
QStringList JlCompress::extractFiles(QString fileCompressed, QStringList files, QString dir) {
|
||||
// Creo lo zip
|
||||
QuaZip zip(fileCompressed);
|
||||
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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Estrae il file fileCompressed nella cartella dir.
|
||||
* Se dir = "" allora il file viene estratto nella cartella corrente.
|
||||
* Se la funzione fallisce cancella i file che si e tentato di estrarre.
|
||||
* Restituisce i nomi assoluti dei file estratti.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * la compressione di un file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
QStringList JlCompress::extractDir(QString fileCompressed, QString dir) {
|
||||
// Apro lo zip
|
||||
QuaZip zip(fileCompressed);
|
||||
if(!zip.open(QuaZip::mdUnzip)) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDir directory(dir);
|
||||
QStringList extracted;
|
||||
if (!zip.goToFirstFile()) {
|
||||
return QStringList();
|
||||
}
|
||||
do {
|
||||
QString name = zip.getCurrentFileName();
|
||||
QString absFilePath = directory.absoluteFilePath(name);
|
||||
if (!extractFile(&zip, "", 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;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Restituisce la lista dei file resenti nel file compresso fileCompressed.
|
||||
* Se la funzione fallisce, restituisce un elenco vuoto.
|
||||
*
|
||||
* La funzione fallisce se:
|
||||
* * non si riesce ad aprire l'oggetto zip;
|
||||
* * la richiesta di informazioni di un file fallisce;
|
||||
* * non si riesce a chiudere l'oggetto zip;
|
||||
*/
|
||||
QStringList JlCompress::getFileList(QString fileCompressed) {
|
||||
// Apro lo zip
|
||||
QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
|
||||
if(!zip->open(QuaZip::mdUnzip)) {
|
||||
delete zip;
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
// Estraggo i nomi dei file
|
||||
QStringList lst;
|
||||
QuaZipFileInfo 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;
|
||||
}
|
||||
|
114
quazip/JlCompress.h
Normal file
114
quazip/JlCompress.h
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef JLCOMPRESSFOLDER_H_
|
||||
#define JLCOMPRESSFOLDER_H_
|
||||
|
||||
#include "quazip.h"
|
||||
#include "quazipfile.h"
|
||||
#include "quazipfileinfo.h"
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
|
||||
/// 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:
|
||||
/// 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 = true);
|
||||
/// 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.
|
||||
/**
|
||||
\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);
|
||||
|
||||
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());
|
||||
/// 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);
|
||||
};
|
||||
|
||||
#endif /* JLCOMPRESSFOLDER_H_ */
|
135
quazip/crypt.h
Normal file
135
quazip/crypt.h
Normal file
@ -0,0 +1,135 @@
|
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This code is a modified version of crypting code in Infozip distribution
|
||||
|
||||
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).
|
||||
|
||||
If you don't need crypting in your application, just define symbols
|
||||
NOCRYPT and NOUNCRYPT.
|
||||
|
||||
This code support the "Traditional PKWARE Encryption".
|
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page
|
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported.
|
||||
*/
|
||||
|
||||
#include "quazip_global.h"
|
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
|
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence
|
||||
*/
|
||||
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab UNUSED)
|
||||
{
|
||||
//(void) pcrc_32_tab; /* avoid "unused parameter" warning */
|
||||
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
|
||||
* unpredictable manner on 16-bit systems; not a problem
|
||||
* with any known compiler so far, though */
|
||||
|
||||
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
|
||||
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Update the encryption keys with the next byte of plain text
|
||||
*/
|
||||
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
|
||||
{
|
||||
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
|
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
|
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
|
||||
{
|
||||
register int keyshift = (int)((*(pkeys+1)) >> 24);
|
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Initialize the encryption keys and the random header according to
|
||||
* the given password.
|
||||
*/
|
||||
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
*(pkeys+0) = 305419896L;
|
||||
*(pkeys+1) = 591751049L;
|
||||
*(pkeys+2) = 878082192L;
|
||||
while (*passwd != '\0') {
|
||||
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
|
||||
passwd++;
|
||||
}
|
||||
}
|
||||
|
||||
#define zdecode(pkeys,pcrc_32_tab,c) \
|
||||
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
|
||||
|
||||
#define zencode(pkeys,pcrc_32_tab,c,t) \
|
||||
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
|
||||
|
||||
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
|
||||
|
||||
#define RAND_HEAD_LEN 12
|
||||
/* "last resort" source for second part of crypt seed pattern */
|
||||
# ifndef ZCR_SEED2
|
||||
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
|
||||
# endif
|
||||
|
||||
static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
|
||||
const char *passwd; /* password string */
|
||||
unsigned char *buf; /* where to write header */
|
||||
int bufSize;
|
||||
unsigned long* pkeys;
|
||||
const unsigned long* pcrc_32_tab;
|
||||
unsigned long crcForCrypting;
|
||||
{
|
||||
int n; /* index in random header */
|
||||
int t; /* temporary */
|
||||
int c; /* random byte */
|
||||
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
|
||||
static unsigned calls = 0; /* ensure different random header each time */
|
||||
|
||||
if (bufSize<RAND_HEAD_LEN)
|
||||
return 0;
|
||||
|
||||
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
|
||||
* output of rand() to get less predictability, since rand() is
|
||||
* often poorly implemented.
|
||||
*/
|
||||
if (++calls == 1)
|
||||
{
|
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
|
||||
}
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
c = (rand() >> 7) & 0xff;
|
||||
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
|
||||
}
|
||||
/* Encrypt random header (last two bytes is high word of crc) */
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
|
||||
}
|
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
|
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
77
quazip/ioapi.h
Normal file
77
quazip/ioapi.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* ioapi.h -- 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.
|
||||
*/
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#define _ZLIBIOAPI_H
|
||||
|
||||
|
||||
#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 (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
|
||||
#define ZCALLBACK CALLBACK
|
||||
#else
|
||||
#define ZCALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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 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));
|
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
|
||||
|
||||
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;
|
||||
|
||||
|
||||
|
||||
void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
|
||||
|
||||
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
|
||||
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
|
||||
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
|
||||
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
146
quazip/qioapi.cpp
Normal file
146
quazip/qioapi.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/* 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 "ioapi.h"
|
||||
#include "quazip_global.h"
|
||||
#include <QIODevice>
|
||||
|
||||
|
||||
/* 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 ZCALLBACK qiodevice_open_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf file,
|
||||
int mode)
|
||||
{
|
||||
QIODevice *iodevice = reinterpret_cast<QIODevice*>(file);
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
|
||||
iodevice->open(QIODevice::ReadOnly);
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
|
||||
iodevice->open(QIODevice::ReadWrite);
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||
iodevice->open(QIODevice::WriteOnly);
|
||||
|
||||
if (iodevice->isOpen()) {
|
||||
if (iodevice->isSequential()) {
|
||||
iodevice->close();
|
||||
return NULL;
|
||||
} else {
|
||||
return iodevice;
|
||||
}
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK qiodevice_read_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf stream,
|
||||
void* buf,
|
||||
uLong size)
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)((QIODevice*)stream)->read((char*)buf,size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK qiodevice_write_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf stream,
|
||||
const void* buf,
|
||||
uLong size)
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)((QIODevice*)stream)->write((char*)buf,size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uLong ZCALLBACK qiodevice_tell_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf stream)
|
||||
{
|
||||
uLong ret;
|
||||
ret = ((QIODevice*)stream)->pos();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK qiodevice_seek_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf stream,
|
||||
uLong offset,
|
||||
int origin)
|
||||
{
|
||||
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 = !((QIODevice*)stream)->seek(qiodevice_seek_result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK qiodevice_close_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf stream)
|
||||
{
|
||||
((QIODevice*)stream)->close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ZCALLBACK qiodevice_error_file_func (
|
||||
voidpf opaque UNUSED,
|
||||
voidpf stream)
|
||||
{
|
||||
// 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 = NULL;
|
||||
}
|
28
quazip/quaadler32.cpp
Normal file
28
quazip/quaadler32.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "quaadler32.h"
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
QuaAdler32::QuaAdler32()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
quint32 QuaAdler32::calculate(const QByteArray &data)
|
||||
{
|
||||
return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() );
|
||||
}
|
||||
|
||||
void QuaAdler32::reset()
|
||||
{
|
||||
checksum = adler32(0L, Z_NULL, 0);
|
||||
}
|
||||
|
||||
void QuaAdler32::update(const QByteArray &buf)
|
||||
{
|
||||
checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() );
|
||||
}
|
||||
|
||||
quint32 QuaAdler32::value()
|
||||
{
|
||||
return checksum;
|
||||
}
|
29
quazip/quaadler32.h
Normal file
29
quazip/quaadler32.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef QUAADLER32_H
|
||||
#define QUAADLER32_H
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
#include "quachecksum32.h"
|
||||
|
||||
/// Adler32 checksum
|
||||
/** \class QuaAdler32 quaadler32.h <quazip/quaadler32.h>
|
||||
* This class wrappers the adler32 function with the QuaChecksum32 interface.
|
||||
* See QuaChecksum32 for more info.
|
||||
*/
|
||||
class QUAZIP_EXPORT QuaAdler32 : public QuaChecksum32
|
||||
{
|
||||
|
||||
public:
|
||||
QuaAdler32();
|
||||
|
||||
quint32 calculate(const QByteArray &data);
|
||||
|
||||
void reset();
|
||||
void update(const QByteArray &buf);
|
||||
quint32 value();
|
||||
|
||||
private:
|
||||
quint32 checksum;
|
||||
};
|
||||
|
||||
#endif //QUAADLER32_H
|
54
quazip/quachecksum32.h
Normal file
54
quazip/quachecksum32.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef QUACHECKSUM32_H
|
||||
#define QUACHECKSUM32_H
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include "quazip_global.h"
|
||||
|
||||
/// Checksum interface.
|
||||
/** \class QuaChecksum32 quachecksum32.h <quazip/quachecksum32.h>
|
||||
* This is an interface for 32 bit checksums.
|
||||
* Classes implementing this interface can calcunate a certin
|
||||
* checksum in a single step:
|
||||
* \code
|
||||
* QChecksum32 *crc32 = new QuaCrc32();
|
||||
* rasoult = crc32->calculate(data);
|
||||
* \endcode
|
||||
* or by streaming the data:
|
||||
* \code
|
||||
* QChecksum32 *crc32 = new QuaCrc32();
|
||||
* while(!fileA.atEnd())
|
||||
* crc32->update(fileA.read(bufSize));
|
||||
* resoultA = crc32->value();
|
||||
* crc32->reset();
|
||||
* while(!fileB.atEnd())
|
||||
* crc32->update(fileB.read(bufSize));
|
||||
* resoultB = crc32->value();
|
||||
* \endcode
|
||||
*/
|
||||
class QUAZIP_EXPORT QuaChecksum32
|
||||
{
|
||||
|
||||
public:
|
||||
///Calculates the checksum for data.
|
||||
/** \a data source data
|
||||
* \return data checksum
|
||||
*
|
||||
* This function has no efect on the value returned by value().
|
||||
*/
|
||||
virtual quint32 calculate(const QByteArray &data) = 0;
|
||||
|
||||
///Resets the calculation on a checksun for a stream.
|
||||
virtual void reset() = 0;
|
||||
|
||||
///Updates the calculated checksum for the stream
|
||||
/** \a buf next portion of data from the stream
|
||||
*/
|
||||
virtual void update(const QByteArray &buf) = 0;
|
||||
|
||||
///Value of the checksum calculated for the stream passed throw update().
|
||||
/** \return checksum
|
||||
*/
|
||||
virtual quint32 value() = 0;
|
||||
};
|
||||
|
||||
#endif //QUACHECKSUM32_H
|
28
quazip/quacrc32.cpp
Normal file
28
quazip/quacrc32.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "quacrc32.h"
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
QuaCrc32::QuaCrc32()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
quint32 QuaCrc32::calculate(const QByteArray &data)
|
||||
{
|
||||
return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() );
|
||||
}
|
||||
|
||||
void QuaCrc32::reset()
|
||||
{
|
||||
checksum = crc32(0L, Z_NULL, 0);
|
||||
}
|
||||
|
||||
void QuaCrc32::update(const QByteArray &buf)
|
||||
{
|
||||
checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() );
|
||||
}
|
||||
|
||||
quint32 QuaCrc32::value()
|
||||
{
|
||||
return checksum;
|
||||
}
|
26
quazip/quacrc32.h
Normal file
26
quazip/quacrc32.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef QUACRC32_H
|
||||
#define QUACRC32_H
|
||||
|
||||
#include "quachecksum32.h"
|
||||
|
||||
///CRC32 checksum
|
||||
/** \class QuaCrc32 quacrc32.h <quazip/quacrc32.h>
|
||||
* This class wrappers the crc32 function with the QuaChecksum32 interface.
|
||||
* See QuaChecksum32 for more info.
|
||||
*/
|
||||
class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 {
|
||||
|
||||
public:
|
||||
QuaCrc32();
|
||||
|
||||
quint32 calculate(const QByteArray &data);
|
||||
|
||||
void reset();
|
||||
void update(const QByteArray &buf);
|
||||
quint32 value();
|
||||
|
||||
private:
|
||||
quint32 checksum;
|
||||
};
|
||||
|
||||
#endif //QUACRC32_H
|
141
quazip/quagzipfile.cpp
Normal file
141
quazip/quagzipfile.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include <QFile>
|
||||
|
||||
#include "quagzipfile.h"
|
||||
|
||||
class QuaGzipFilePrivate {
|
||||
friend class QuaGzipFile;
|
||||
QString fileName;
|
||||
gzFile gzd;
|
||||
inline QuaGzipFilePrivate(): gzd(NULL) {}
|
||||
inline QuaGzipFilePrivate(const QString &fileName):
|
||||
fileName(fileName), gzd(NULL) {}
|
||||
template<typename FileId> bool open(FileId id,
|
||||
QIODevice::OpenMode mode, QString &error);
|
||||
gzFile open(int fd, const char *modeString);
|
||||
gzFile open(const QString &name, const char *modeString);
|
||||
};
|
||||
|
||||
gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString)
|
||||
{
|
||||
return gzopen(QFile::encodeName(name).constData(), modeString);
|
||||
}
|
||||
|
||||
gzFile QuaGzipFilePrivate::open(int fd, const char *modeString)
|
||||
{
|
||||
return gzdopen(fd, modeString);
|
||||
}
|
||||
|
||||
template<typename FileId>
|
||||
bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode,
|
||||
QString &error)
|
||||
{
|
||||
char modeString[2];
|
||||
modeString[0] = modeString[1] = '\0';
|
||||
if ((mode & QIODevice::ReadOnly) != 0
|
||||
&& (mode & QIODevice::WriteOnly) != 0) {
|
||||
error = QuaGzipFile::trUtf8("Opening gzip for both reading"
|
||||
" and writing is not supported");
|
||||
return false;
|
||||
} else if ((mode & QIODevice::ReadOnly) != 0) {
|
||||
modeString[0] = 'r';
|
||||
} else if ((mode & QIODevice::WriteOnly) != 0) {
|
||||
modeString[0] = 'w';
|
||||
} else {
|
||||
error = QuaGzipFile::trUtf8("You can open a gzip either for reading"
|
||||
" or for writing. Which is it?");
|
||||
return false;
|
||||
}
|
||||
gzd = open(id, modeString);
|
||||
if (gzd == NULL) {
|
||||
error = QuaGzipFile::trUtf8("Could not gzopen() file");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QuaGzipFile::QuaGzipFile():
|
||||
d(new QuaGzipFilePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
QuaGzipFile::QuaGzipFile(QObject *parent):
|
||||
QIODevice(parent),
|
||||
d(new QuaGzipFilePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent):
|
||||
QIODevice(parent),
|
||||
d(new QuaGzipFilePrivate(fileName))
|
||||
{
|
||||
}
|
||||
|
||||
QuaGzipFile::~QuaGzipFile()
|
||||
{
|
||||
if (isOpen()) {
|
||||
close();
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QuaGzipFile::setFileName(const QString& fileName)
|
||||
{
|
||||
d->fileName = fileName;
|
||||
}
|
||||
|
||||
QString QuaGzipFile::getFileName() const
|
||||
{
|
||||
return d->fileName;
|
||||
}
|
||||
|
||||
bool QuaGzipFile::isSequential() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuaGzipFile::open(QIODevice::OpenMode mode)
|
||||
{
|
||||
QString error;
|
||||
if (!d->open(d->fileName, mode, error)) {
|
||||
setErrorString(error);
|
||||
return false;
|
||||
}
|
||||
return QIODevice::open(mode);
|
||||
}
|
||||
|
||||
bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode)
|
||||
{
|
||||
QString error;
|
||||
if (!d->open(fd, mode, error)) {
|
||||
setErrorString(error);
|
||||
return false;
|
||||
}
|
||||
return QIODevice::open(mode);
|
||||
}
|
||||
|
||||
bool QuaGzipFile::flush()
|
||||
{
|
||||
return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK;
|
||||
}
|
||||
|
||||
void QuaGzipFile::close()
|
||||
{
|
||||
QIODevice::close();
|
||||
gzclose(d->gzd);
|
||||
}
|
||||
|
||||
qint64 QuaGzipFile::readData(char *data, qint64 maxSize)
|
||||
{
|
||||
return gzread(d->gzd, (voidp)data, (unsigned)maxSize);
|
||||
}
|
||||
|
||||
qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize)
|
||||
{
|
||||
if (maxSize == 0)
|
||||
return 0;
|
||||
int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize);
|
||||
if (written == 0)
|
||||
return -1;
|
||||
else
|
||||
return written;
|
||||
}
|
35
quazip/quagzipfile.h
Normal file
35
quazip/quagzipfile.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef QUAZIP_QUAGZIPFILE_H
|
||||
#define QUAZIP_QUAGZIPFILE_H
|
||||
|
||||
#include <QIODevice>
|
||||
#include "quazip_global.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
class QuaGzipFilePrivate;
|
||||
|
||||
class QUAZIP_EXPORT QuaGzipFile: public QIODevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QuaGzipFile();
|
||||
QuaGzipFile(QObject *parent);
|
||||
QuaGzipFile(const QString &fileName, QObject *parent = NULL);
|
||||
virtual ~QuaGzipFile();
|
||||
void setFileName(const QString& fileName);
|
||||
QString getFileName() const;
|
||||
virtual bool isSequential() const;
|
||||
virtual bool open(QIODevice::OpenMode mode);
|
||||
virtual bool open(int fd, QIODevice::OpenMode mode);
|
||||
virtual bool flush();
|
||||
virtual void close();
|
||||
protected:
|
||||
virtual qint64 readData(char *data, qint64 maxSize);
|
||||
virtual qint64 writeData(const char *data, qint64 maxSize);
|
||||
private:
|
||||
// not implemented by design to disable copy
|
||||
QuaGzipFile(const QuaGzipFile &that);
|
||||
QuaGzipFile& operator=(const QuaGzipFile &that);
|
||||
QuaGzipFilePrivate *d;
|
||||
};
|
||||
|
||||
#endif // QUAZIP_QUAGZIPFILE_H
|
283
quazip/quaziodevice.cpp
Normal file
283
quazip/quaziodevice.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
#include "quaziodevice.h"
|
||||
|
||||
#define QUAZIO_INBUFSIZE 4096
|
||||
#define QUAZIO_OUTBUFSIZE 4096
|
||||
|
||||
class QuaZIODevicePrivate {
|
||||
friend class QuaZIODevice;
|
||||
QuaZIODevicePrivate(QIODevice *io);
|
||||
~QuaZIODevicePrivate();
|
||||
QIODevice *io;
|
||||
z_stream zins;
|
||||
z_stream zouts;
|
||||
char *inBuf;
|
||||
int inBufPos;
|
||||
int inBufSize;
|
||||
char *outBuf;
|
||||
int outBufPos;
|
||||
int outBufSize;
|
||||
bool zBufError;
|
||||
int doFlush(QString &error);
|
||||
};
|
||||
|
||||
QuaZIODevicePrivate::QuaZIODevicePrivate(QIODevice *io):
|
||||
io(io),
|
||||
inBuf(NULL),
|
||||
inBufPos(0),
|
||||
inBufSize(0),
|
||||
outBuf(NULL),
|
||||
outBufPos(0),
|
||||
outBufSize(0),
|
||||
zBufError(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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// #define QUAZIP_ZIODEVICE_DEBUG_OUTPUT
|
||||
// #define QUAZIP_ZIODEVICE_DEBUG_INPUT
|
||||
#ifdef QUAZIP_ZIODEVICE_DEBUG_OUTPUT
|
||||
#include <QFile>
|
||||
static QFile debug;
|
||||
#endif
|
||||
#ifdef QUAZIP_ZIODEVICE_DEBUG_INPUT
|
||||
#include <QFile>
|
||||
static QFile indebug;
|
||||
#endif
|
||||
|
||||
QuaZIODevice::QuaZIODevice(QIODevice *io, QObject *parent):
|
||||
QIODevice(parent),
|
||||
d(new QuaZIODevicePrivate(io))
|
||||
{
|
||||
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::ReadOnly) != 0) {
|
||||
if (inflateInit(&d->zins) != Z_OK) {
|
||||
setErrorString(d->zins.msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((mode & QIODevice::WriteOnly) != 0) {
|
||||
if (deflateInit(&d->zouts, Z_DEFAULT_COMPRESSION) != Z_OK) {
|
||||
setErrorString(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);
|
||||
}
|
||||
}
|
||||
if ((openMode() & QIODevice::WriteOnly) != 0) {
|
||||
flush();
|
||||
if (deflateEnd(&d->zouts) != Z_OK) {
|
||||
setErrorString(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;
|
||||
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;
|
||||
}
|
||||
|
||||
bool QuaZIODevice::isSequential() const
|
||||
{
|
||||
return true;
|
||||
}
|
27
quazip/quaziodevice.h
Normal file
27
quazip/quaziodevice.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef QUAZIP_QUAZIODEVICE_H
|
||||
#define QUAZIP_QUAZIODEVICE_H
|
||||
|
||||
#include <QIODevice>
|
||||
#include "quazip_global.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
class QuaZIODevicePrivate;
|
||||
|
||||
class QUAZIP_EXPORT QuaZIODevice: public QIODevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QuaZIODevice(QIODevice *io, QObject *parent = NULL);
|
||||
~QuaZIODevice();
|
||||
virtual bool flush();
|
||||
virtual bool open(QIODevice::OpenMode);
|
||||
virtual void close();
|
||||
QIODevice *getIoDevice() const;
|
||||
virtual bool isSequential() const;
|
||||
protected:
|
||||
virtual qint64 readData(char *data, qint64 maxSize);
|
||||
virtual qint64 writeData(const char *data, qint64 maxSize);
|
||||
private:
|
||||
QuaZIODevicePrivate *d;
|
||||
};
|
||||
#endif // QUAZIP_QUAZIODEVICE_H
|
554
quazip/quazip.cpp
Normal file
554
quazip/quazip.cpp
Normal file
@ -0,0 +1,554 @@
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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 <QtCore/QFile>
|
||||
#include <QtCore/QFlags>
|
||||
|
||||
#include "quazip.h"
|
||||
|
||||
/// 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:
|
||||
/// The pointer to the corresponding QuaZip instance.
|
||||
QuaZip *q;
|
||||
/// The codec for file names.
|
||||
QTextCodec *fileNameCodec;
|
||||
/// The codec for comments.
|
||||
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 constructor for the corresponding QuaZip constructor.
|
||||
inline QuaZipPrivate(QuaZip *q):
|
||||
q(q),
|
||||
fileNameCodec(QTextCodec::codecForLocale()),
|
||||
commentCodec(QTextCodec::codecForLocale()),
|
||||
ioDevice(NULL),
|
||||
mode(QuaZip::mdNotOpen),
|
||||
hasCurrentFile_f(false),
|
||||
zipError(UNZ_OK),
|
||||
dataDescriptorWritingEnabled(true) {}
|
||||
/// The constructor for the corresponding QuaZip constructor.
|
||||
inline QuaZipPrivate(QuaZip *q, const QString &zipName):
|
||||
q(q),
|
||||
fileNameCodec(QTextCodec::codecForLocale()),
|
||||
commentCodec(QTextCodec::codecForLocale()),
|
||||
zipName(zipName),
|
||||
ioDevice(NULL),
|
||||
mode(QuaZip::mdNotOpen),
|
||||
hasCurrentFile_f(false),
|
||||
zipError(UNZ_OK),
|
||||
dataDescriptorWritingEnabled(true) {}
|
||||
/// The constructor for the corresponding QuaZip constructor.
|
||||
inline QuaZipPrivate(QuaZip *q, QIODevice *ioDevice):
|
||||
q(q),
|
||||
fileNameCodec(QTextCodec::codecForLocale()),
|
||||
commentCodec(QTextCodec::codecForLocale()),
|
||||
ioDevice(ioDevice),
|
||||
mode(QuaZip::mdNotOpen),
|
||||
hasCurrentFile_f(false),
|
||||
zipError(UNZ_OK),
|
||||
dataDescriptorWritingEnabled(true) {}
|
||||
/// Returns either a list of file names or a list of QuaZipFileInfo.
|
||||
template<typename TFileInfo>
|
||||
bool getFileInfoList(QList<TFileInfo> *result) const;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
switch(mode) {
|
||||
case mdUnzip:
|
||||
p->unzFile_f=unzOpen2(ioDevice, ioApi);
|
||||
if(p->unzFile_f!=NULL) {
|
||||
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:
|
||||
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) {
|
||||
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());
|
||||
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;
|
||||
}
|
||||
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_info globalInfo;
|
||||
if((fakeThis->p->zipError=unzGetGlobalInfo(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_info globalInfo;
|
||||
QByteArray comment;
|
||||
if((fakeThis->p->zipError=unzGetGlobalInfo(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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
bool sens = convertCaseSensitivity(cs) == Qt::CaseSensitive;
|
||||
QString lower, current;
|
||||
if(!sens) lower=fileName.toLower();
|
||||
p->hasCurrentFile_f=false;
|
||||
for(bool more=goToFirstFile(); 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
|
||||
{
|
||||
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_info info_z;
|
||||
QByteArray fileName;
|
||||
QByteArray extra;
|
||||
QByteArray comment;
|
||||
if(info==NULL) return false;
|
||||
if(!isOpen()||!hasCurrentFile()) return false;
|
||||
if((fakeThis->p->zipError=unzGetCurrentFileInfo(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=unzGetCurrentFileInfo(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->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));
|
||||
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=unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(),
|
||||
NULL, 0, NULL, 0))!=UNZ_OK)
|
||||
return QString();
|
||||
return p->fileNameCodec->toUnicode(fileName.constData());
|
||||
}
|
||||
|
||||
void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec)
|
||||
{
|
||||
p->fileNameCodec=fileNameCodec;
|
||||
}
|
||||
|
||||
void QuaZip::setFileNameCodec(const char *fileNameCodecName)
|
||||
{
|
||||
p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName);
|
||||
}
|
||||
|
||||
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<>
|
||||
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>();
|
||||
}
|
||||
|
||||
Qt::CaseSensitivity QuaZip::convertCaseSensitivity(QuaZip::CaseSensitivity cs)
|
||||
{
|
||||
if (cs == csDefault) {
|
||||
#ifdef Q_WS_WIN
|
||||
return Qt::CaseInsensitive;
|
||||
#else
|
||||
return Qt::CaseSensitive;
|
||||
#endif
|
||||
} else {
|
||||
return cs == csSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||
}
|
||||
}
|
411
quazip/quazip.h
Normal file
411
quazip/quazip.h
Normal file
@ -0,0 +1,411 @@
|
||||
#ifndef QUA_ZIP_H
|
||||
#define QUA_ZIP_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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 "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.
|
||||
};
|
||||
static Qt::CaseSensitivity convertCaseSensitivity(CaseSensitivity);
|
||||
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 the behaviour is defined by
|
||||
* the device implementation, but generally it is not a very good
|
||||
* idea. For example, QFile will at least issue a warning.
|
||||
*
|
||||
* \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 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. The
|
||||
* underlying QIODevice is also closed, regardless of whether it was
|
||||
* set explicitly or not. */
|
||||
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);
|
||||
/// 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 "" comment in the QuaZip::mdAdd mode.
|
||||
* A null comment is the default and it means "don't change
|
||||
* the comment". 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;
|
||||
* - \a info is \c NULL;
|
||||
*
|
||||
* In all these cases getZipError() returns \c UNZ_OK since there
|
||||
* is no ZIP/UNZIP API call.
|
||||
**/
|
||||
bool getCurrentFileInfo(QuaZipFileInfo* 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.
|
||||
|
||||
\param enabled If \c true, enable local descriptor writing,
|
||||
disable it otherwise.
|
||||
|
||||
\sa QuaZipFile::setDataDescriptorWritingEnabled()
|
||||
*/
|
||||
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).
|
||||
\sa getFileNameList()
|
||||
*/
|
||||
QList<QuaZipFileInfo> getFileInfoList() const;
|
||||
};
|
||||
|
||||
#endif
|
55
quazip/quazip_global.h
Normal file
55
quazip/quazip_global.h
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef QUAZIP_GLOBAL_H
|
||||
#define QUAZIP_GLOBAL_H
|
||||
|
||||
#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 UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
|
||||
#endif // QUAZIP_GLOBAL_H
|
507
quazip/quazipdir.cpp
Normal file
507
quazip/quazipdir.cpp
Normal file
@ -0,0 +1,507 @@
|
||||
#include "quazipdir.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QSharedData>
|
||||
|
||||
class QuaZipDirPrivate: public QSharedData {
|
||||
friend class QuaZipDir;
|
||||
private:
|
||||
QuaZipDirPrivate(QuaZip *zip, const QString &dir = QString()):
|
||||
zip(zip), dir(dir), caseSensitivity(QuaZip::csDefault),
|
||||
filter(QDir::NoFilter), sorting(QDir::NoSort) {}
|
||||
QuaZip *zip;
|
||||
QString dir;
|
||||
QuaZip::CaseSensitivity caseSensitivity;
|
||||
QDir::Filters filter;
|
||||
QStringList nameFilters;
|
||||
QDir::SortFlags sorting;
|
||||
template<typename TFileInfoList>
|
||||
bool entryInfoList(QStringList nameFilters, QDir::Filters filter,
|
||||
QDir::SortFlags sort, TFileInfoList &result) const;
|
||||
inline QString simplePath() const {return QDir::cleanPath(dir);}
|
||||
};
|
||||
|
||||
QuaZipDir::QuaZipDir(const QuaZipDir &that):
|
||||
d(that.d)
|
||||
{
|
||||
}
|
||||
|
||||
QuaZipDir::QuaZipDir(QuaZip *zip, const QString &dir):
|
||||
d(new QuaZipDirPrivate(zip, dir))
|
||||
{
|
||||
if (d->dir.startsWith('/'))
|
||||
d->dir = d->dir.mid(1);
|
||||
}
|
||||
|
||||
QuaZipDir::~QuaZipDir()
|
||||
{
|
||||
}
|
||||
|
||||
bool QuaZipDir::operator==(const QuaZipDir &that)
|
||||
{
|
||||
return d->zip == that.d->zip && d->dir == that.d->dir;
|
||||
}
|
||||
|
||||
QuaZipDir& QuaZipDir::operator=(const QuaZipDir &that)
|
||||
{
|
||||
this->d = that.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QString QuaZipDir::operator[](int pos) const
|
||||
{
|
||||
return entryList().at(pos);
|
||||
}
|
||||
|
||||
QuaZip::CaseSensitivity QuaZipDir::caseSensitivity() const
|
||||
{
|
||||
return d->caseSensitivity;
|
||||
}
|
||||
|
||||
bool QuaZipDir::cd(const QString &directoryName)
|
||||
{
|
||||
if (directoryName == "/") {
|
||||
d->dir = "";
|
||||
return true;
|
||||
}
|
||||
QString dirName = directoryName;
|
||||
if (dirName.endsWith('/'))
|
||||
dirName.chop(1);
|
||||
if (dirName.contains('/')) {
|
||||
QuaZipDir dir(*this);
|
||||
if (dirName.startsWith('/')) {
|
||||
#ifdef QUAZIP_QUAZIPDIR_DEBUG
|
||||
qDebug("QuaZipDir::cd(%s): going to /",
|
||||
dirName.toUtf8().constData());
|
||||
#endif
|
||||
if (!dir.cd("/"))
|
||||
return false;
|
||||
}
|
||||
QStringList path = dirName.split('/', QString::SkipEmptyParts);
|
||||
for (QStringList::const_iterator i = path.constBegin();
|
||||
i != path.end();
|
||||
++i) {
|
||||
const QString &step = *i;
|
||||
#ifdef QUAZIP_QUAZIPDIR_DEBUG
|
||||
qDebug("QuaZipDir::cd(%s): going to %s",
|
||||
dirName.toUtf8().constData(),
|
||||
step.toUtf8().constData());
|
||||
#endif
|
||||
if (!dir.cd(step))
|
||||
return false;
|
||||
}
|
||||
d->dir = dir.path();
|
||||
return true;
|
||||
} else { // no '/'
|
||||
if (dirName == ".") {
|
||||
return true;
|
||||
} else if (dirName == "..") {
|
||||
if (isRoot()) {
|
||||
return false;
|
||||
} else {
|
||||
int slashPos = d->dir.lastIndexOf('/');
|
||||
if (slashPos == -1) {
|
||||
d->dir = "";
|
||||
} else {
|
||||
d->dir = d->dir.left(slashPos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else { // a simple subdirectory
|
||||
if (exists(dirName)) {
|
||||
if (isRoot())
|
||||
d->dir = dirName;
|
||||
else
|
||||
d->dir += "/" + dirName;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QuaZipDir::cdUp()
|
||||
{
|
||||
return cd("..");
|
||||
}
|
||||
|
||||
uint QuaZipDir::count() const
|
||||
{
|
||||
return entryList().count();
|
||||
}
|
||||
|
||||
QString QuaZipDir::dirName() const
|
||||
{
|
||||
return QDir(d->dir).dirName();
|
||||
}
|
||||
|
||||
QuaZipFileInfo QuaZipDir_getFileInfo(QuaZip *zip, bool *ok,
|
||||
const QString &relativeName,
|
||||
bool isReal)
|
||||
{
|
||||
QuaZipFileInfo info;
|
||||
if (isReal) {
|
||||
*ok = zip->getCurrentFileInfo(&info);
|
||||
} else {
|
||||
*ok = true;
|
||||
info.compressedSize = 0;
|
||||
info.crc = 0;
|
||||
info.diskNumberStart = 0;
|
||||
info.externalAttr = 0;
|
||||
info.flags = 0;
|
||||
info.internalAttr = 0;
|
||||
info.method = 0;
|
||||
info.uncompressedSize = 0;
|
||||
info.versionCreated = info.versionNeeded = 0;
|
||||
}
|
||||
info.name = relativeName;
|
||||
return info;
|
||||
}
|
||||
|
||||
template<typename TFileInfoList>
|
||||
void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo> &from, TFileInfoList &to);
|
||||
|
||||
template<>
|
||||
void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo> &from, QList<QuaZipFileInfo> &to)
|
||||
{
|
||||
to = from;
|
||||
}
|
||||
|
||||
template<>
|
||||
void QuaZipDir_convertInfoList(const QList<QuaZipFileInfo> &from, QStringList &to)
|
||||
{
|
||||
to.clear();
|
||||
for (QList<QuaZipFileInfo>::const_iterator i = from.constBegin();
|
||||
i != from.constEnd();
|
||||
++i) {
|
||||
to.append(i->name);
|
||||
}
|
||||
}
|
||||
|
||||
// utility class to restore the current file
|
||||
class QuaZipDirRestoreCurrent {
|
||||
public:
|
||||
inline QuaZipDirRestoreCurrent(QuaZip *zip):
|
||||
zip(zip), currentFile(zip->getCurrentFileName()) {}
|
||||
inline ~QuaZipDirRestoreCurrent()
|
||||
{
|
||||
zip->setCurrentFile(currentFile);
|
||||
}
|
||||
private:
|
||||
QuaZip *zip;
|
||||
QString currentFile;
|
||||
};
|
||||
|
||||
class QuaZipDirComparator
|
||||
{
|
||||
private:
|
||||
QDir::SortFlags sort;
|
||||
static QString getExtension(const QString &name);
|
||||
int compareStrings(const QString &string1, const QString &string2);
|
||||
public:
|
||||
inline QuaZipDirComparator(QDir::SortFlags sort): sort(sort) {}
|
||||
bool operator()(const QuaZipFileInfo &info1, const QuaZipFileInfo &info2);
|
||||
};
|
||||
|
||||
QString QuaZipDirComparator::getExtension(const QString &name)
|
||||
{
|
||||
if (name.endsWith('.') || name.indexOf('.', 1) == -1) {
|
||||
return "";
|
||||
} else {
|
||||
return name.mid(name.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int QuaZipDirComparator::compareStrings(const QString &string1,
|
||||
const QString &string2)
|
||||
{
|
||||
if (sort & QDir::LocaleAware) {
|
||||
if (sort & QDir::IgnoreCase) {
|
||||
return string1.toLower().localeAwareCompare(string2.toLower());
|
||||
} else {
|
||||
return string1.localeAwareCompare(string2);
|
||||
}
|
||||
} else {
|
||||
return string1.compare(string2, (sort & QDir::IgnoreCase)
|
||||
? Qt::CaseInsensitive : Qt::CaseSensitive);
|
||||
}
|
||||
}
|
||||
|
||||
bool QuaZipDirComparator::operator()(const QuaZipFileInfo &info1,
|
||||
const QuaZipFileInfo &info2)
|
||||
{
|
||||
QDir::SortFlags order = sort
|
||||
& (QDir::Name | QDir::Time | QDir::Size | QDir::Type);
|
||||
if ((sort & QDir::DirsFirst) == QDir::DirsFirst
|
||||
|| (sort & QDir::DirsLast) == QDir::DirsLast) {
|
||||
if (info1.name.endsWith('/') && !info2.name.endsWith('/'))
|
||||
return (sort & QDir::DirsFirst) == QDir::DirsFirst;
|
||||
else if (!info1.name.endsWith('/') && info2.name.endsWith('/'))
|
||||
return (sort & QDir::DirsLast) == QDir::DirsLast;
|
||||
}
|
||||
bool result;
|
||||
int extDiff;
|
||||
switch (order) {
|
||||
case QDir::Name:
|
||||
result = compareStrings(info1.name, info2.name) < 0;
|
||||
break;
|
||||
case QDir::Type:
|
||||
extDiff = compareStrings(getExtension(info1.name),
|
||||
getExtension(info2.name));
|
||||
if (extDiff == 0) {
|
||||
result = compareStrings(info1.name, info2.name) < 0;
|
||||
} else {
|
||||
result = extDiff < 0;
|
||||
}
|
||||
break;
|
||||
case QDir::Size:
|
||||
if (info1.uncompressedSize == info2.uncompressedSize) {
|
||||
result = compareStrings(info1.name, info2.name) < 0;
|
||||
} else {
|
||||
result = info1.uncompressedSize < info2.uncompressedSize;
|
||||
}
|
||||
break;
|
||||
case QDir::Time:
|
||||
if (info1.dateTime == info2.dateTime) {
|
||||
result = compareStrings(info1.name, info2.name) < 0;
|
||||
} else {
|
||||
result = info1.dateTime < info2.dateTime;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qWarning("QuaZipDirComparator(): Invalid sort mode 0x%2X",
|
||||
static_cast<unsigned>(sort));
|
||||
return false;
|
||||
}
|
||||
return (sort & QDir::Reversed) ? !result : result;
|
||||
}
|
||||
|
||||
template<typename TFileInfoList>
|
||||
bool QuaZipDirPrivate::entryInfoList(QStringList nameFilters,
|
||||
QDir::Filters filter, QDir::SortFlags sort, TFileInfoList &result) const
|
||||
{
|
||||
QString basePath = simplePath();
|
||||
if (!basePath.isEmpty())
|
||||
basePath += "/";
|
||||
int baseLength = basePath.length();
|
||||
result.clear();
|
||||
QuaZipDirRestoreCurrent saveCurrent(zip);
|
||||
if (!zip->goToFirstFile()) {
|
||||
return zip->getZipError() == UNZ_OK;
|
||||
}
|
||||
QDir::Filters fltr = filter;
|
||||
if (fltr == QDir::NoFilter)
|
||||
fltr = this->filter;
|
||||
if (fltr == QDir::NoFilter)
|
||||
fltr = QDir::AllEntries;
|
||||
QStringList nmfltr = nameFilters;
|
||||
if (nmfltr.isEmpty())
|
||||
nmfltr = this->nameFilters;
|
||||
QSet<QString> dirsFound;
|
||||
QList<QuaZipFileInfo> list;
|
||||
do {
|
||||
QString name = zip->getCurrentFileName();
|
||||
if (!name.startsWith(basePath))
|
||||
continue;
|
||||
QString relativeName = name.mid(baseLength);
|
||||
bool isDir = false;
|
||||
bool isReal = true;
|
||||
if (relativeName.contains('/')) {
|
||||
int indexOfSlash = relativeName.indexOf('/');
|
||||
// something like "subdir/"
|
||||
isReal = indexOfSlash == relativeName.length() - 1;
|
||||
relativeName = relativeName.left(indexOfSlash + 1);
|
||||
if (dirsFound.contains(relativeName))
|
||||
continue;
|
||||
isDir = true;
|
||||
}
|
||||
dirsFound.insert(relativeName);
|
||||
if ((fltr & QDir::Dirs) == 0 && isDir)
|
||||
continue;
|
||||
if ((fltr & QDir::Files) == 0 && !isDir)
|
||||
continue;
|
||||
if (!nmfltr.isEmpty() && QDir::match(nmfltr, relativeName))
|
||||
continue;
|
||||
bool ok;
|
||||
QuaZipFileInfo info = QuaZipDir_getFileInfo(zip, &ok, relativeName,
|
||||
isReal);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
list.append(info);
|
||||
} while (zip->goToNextFile());
|
||||
QDir::SortFlags srt = sort;
|
||||
if (srt == QDir::NoSort)
|
||||
srt = sorting;
|
||||
#ifdef QUAZIP_QUAZIPDIR_DEBUG
|
||||
qDebug("QuaZipDirPrivate::entryInfoList(): before sort:");
|
||||
foreach (QuaZipFileInfo info, list) {
|
||||
qDebug("%s\t%s", info.name.toUtf8().constData(),
|
||||
info.dateTime.toString(Qt::ISODate).toUtf8().constData());
|
||||
}
|
||||
#endif
|
||||
if (srt != QDir::NoSort && (srt & QDir::Unsorted) != QDir::Unsorted) {
|
||||
if (QuaZip::convertCaseSensitivity(caseSensitivity)
|
||||
== Qt::CaseInsensitive)
|
||||
srt |= QDir::IgnoreCase;
|
||||
QuaZipDirComparator lessThan(srt);
|
||||
qSort(list.begin(), list.end(), lessThan);
|
||||
}
|
||||
QuaZipDir_convertInfoList(list, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QuaZipFileInfo> QuaZipDir::entryInfoList(const QStringList &nameFilters,
|
||||
QDir::Filters filters, QDir::SortFlags sort) const
|
||||
{
|
||||
QList<QuaZipFileInfo> result;
|
||||
if (d->entryInfoList(nameFilters, filters, sort, result))
|
||||
return result;
|
||||
else
|
||||
return QList<QuaZipFileInfo>();
|
||||
}
|
||||
|
||||
QList<QuaZipFileInfo> QuaZipDir::entryInfoList(QDir::Filters filters,
|
||||
QDir::SortFlags sort) const
|
||||
{
|
||||
return entryInfoList(QStringList(), filters, sort);
|
||||
}
|
||||
|
||||
QStringList QuaZipDir::entryList(const QStringList &nameFilters,
|
||||
QDir::Filters filters, QDir::SortFlags sort) const
|
||||
{
|
||||
QStringList result;
|
||||
if (d->entryInfoList(nameFilters, filters, sort, result))
|
||||
return result;
|
||||
else
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QStringList QuaZipDir::entryList(QDir::Filters filters,
|
||||
QDir::SortFlags sort) const
|
||||
{
|
||||
return entryList(QStringList(), filters, sort);
|
||||
}
|
||||
|
||||
bool QuaZipDir::exists(const QString &filePath) const
|
||||
{
|
||||
if (filePath == "/")
|
||||
return true;
|
||||
QString fileName = filePath;
|
||||
if (fileName.endsWith('/'))
|
||||
fileName.chop(1);
|
||||
if (fileName.contains('/')) {
|
||||
QFileInfo fileInfo(fileName);
|
||||
#ifdef QUAZIP_QUAZIPDIR_DEBUG
|
||||
qDebug("QuaZipDir::exists(): fileName=%s, fileInfo.fileName()=%s, "
|
||||
"fileInfo.path()=%s", fileName.toUtf8().constData(),
|
||||
fileInfo.fileName().toUtf8().constData(),
|
||||
fileInfo.path().toUtf8().constData());
|
||||
#endif
|
||||
QuaZipDir dir(*this);
|
||||
return dir.cd(fileInfo.path()) && dir.exists(fileInfo.fileName());
|
||||
} else {
|
||||
if (fileName == "..") {
|
||||
return !isRoot();
|
||||
} else if (fileName == ".") {
|
||||
return true;
|
||||
} else {
|
||||
QStringList entries = entryList(QDir::AllEntries, QDir::NoSort);
|
||||
#ifdef QUAZIP_QUAZIPDIR_DEBUG
|
||||
qDebug("QuaZipDir::exists(): looking for %s",
|
||||
fileName.toUtf8().constData());
|
||||
for (QStringList::const_iterator i = entries.constBegin();
|
||||
i != entries.constEnd();
|
||||
++i) {
|
||||
qDebug("QuaZipDir::exists(): entry: %s",
|
||||
i->toUtf8().constData());
|
||||
}
|
||||
#endif
|
||||
Qt::CaseSensitivity cs = QuaZip::convertCaseSensitivity(
|
||||
d->caseSensitivity);
|
||||
if (filePath.endsWith('/')) {
|
||||
return entries.contains(filePath, cs);
|
||||
} else {
|
||||
return entries.contains(fileName, cs)
|
||||
|| entries.contains(fileName + "/", cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QuaZipDir::exists() const
|
||||
{
|
||||
QDir thisDir(d->dir);
|
||||
return QuaZipDir(d->zip, thisDir.filePath("..")).exists(thisDir.dirName());
|
||||
}
|
||||
|
||||
QString QuaZipDir::filePath(const QString &fileName) const
|
||||
{
|
||||
return QDir(d->dir).filePath(fileName);
|
||||
}
|
||||
|
||||
QDir::Filters QuaZipDir::filter()
|
||||
{
|
||||
return d->filter;
|
||||
}
|
||||
|
||||
bool QuaZipDir::isRoot() const
|
||||
{
|
||||
return d->simplePath().isEmpty();
|
||||
}
|
||||
|
||||
QStringList QuaZipDir::nameFilters() const
|
||||
{
|
||||
return d->nameFilters;
|
||||
}
|
||||
|
||||
QString QuaZipDir::path() const
|
||||
{
|
||||
return d->dir;
|
||||
}
|
||||
|
||||
QString QuaZipDir::relativeFilePath(const QString &fileName) const
|
||||
{
|
||||
return QDir(d->dir).relativeFilePath(fileName);
|
||||
}
|
||||
|
||||
void QuaZipDir::setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
d->caseSensitivity = caseSensitivity;
|
||||
}
|
||||
|
||||
void QuaZipDir::setFilter(QDir::Filters filters)
|
||||
{
|
||||
d->filter = filters;
|
||||
}
|
||||
|
||||
void QuaZipDir::setNameFilters(const QStringList &nameFilters)
|
||||
{
|
||||
d->nameFilters = nameFilters;
|
||||
}
|
||||
|
||||
void QuaZipDir::setPath(const QString &path)
|
||||
{
|
||||
QString newDir = path;
|
||||
if (newDir == "/") {
|
||||
d->dir = "";
|
||||
} else {
|
||||
if (newDir.endsWith('/'))
|
||||
newDir.chop(1);
|
||||
if (newDir.startsWith('/'))
|
||||
newDir = newDir.mid(1);
|
||||
d->dir = newDir;
|
||||
}
|
||||
}
|
||||
|
||||
void QuaZipDir::setSorting(QDir::SortFlags sort)
|
||||
{
|
||||
d->sorting = sort;
|
||||
}
|
||||
|
||||
QDir::SortFlags QuaZipDir::sorting() const
|
||||
{
|
||||
return d->sorting;
|
||||
}
|
171
quazip/quazipdir.h
Normal file
171
quazip/quazipdir.h
Normal file
@ -0,0 +1,171 @@
|
||||
#ifndef QUAZIP_QUAZIPDIR_H
|
||||
#define QUAZIP_QUAZIPDIR_H
|
||||
|
||||
class QuaZipDirPrivate;
|
||||
|
||||
#include "quazip.h"
|
||||
#include "quazipfileinfo.h"
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include <QSharedDataPointer>
|
||||
|
||||
/// Provides ZIP archive navigation.
|
||||
/**
|
||||
* This class is modelled after QDir, and is designed to provide similar
|
||||
* features for ZIP archives.
|
||||
*
|
||||
* The only significant difference from QDir is that the root path is not
|
||||
* '/', but an empty string since that's how the file paths are stored in
|
||||
* the archive. However, QuaZipDir understands the paths starting with
|
||||
* '/'. It is important in a few places:
|
||||
*
|
||||
* - In the cd() function.
|
||||
* - In the constructor.
|
||||
* - In the exists() function.
|
||||
*
|
||||
* Note that since ZIP uses '/' on all platforms, the '\' separator is
|
||||
* not supported.
|
||||
*/
|
||||
class QUAZIP_EXPORT QuaZipDir {
|
||||
private:
|
||||
QSharedDataPointer<QuaZipDirPrivate> d;
|
||||
public:
|
||||
/// The copy constructor.
|
||||
QuaZipDir(const QuaZipDir &that);
|
||||
/// Constructs a QuaZipDir instance pointing to the specified directory.
|
||||
/**
|
||||
If \a dir is not specified, points to the root of the archive.
|
||||
The same happens if the \a dir is "/".
|
||||
*/
|
||||
QuaZipDir(QuaZip *zip, const QString &dir = QString());
|
||||
/// Destructor.
|
||||
~QuaZipDir();
|
||||
/// The assignment operator.
|
||||
bool operator==(const QuaZipDir &that);
|
||||
/// operator!=
|
||||
/**
|
||||
\return \c true if either this and \a that use different QuaZip
|
||||
instances or if they point to different directories.
|
||||
*/
|
||||
inline bool operator!=(const QuaZipDir &that) {return !operator==(that);}
|
||||
/// operator==
|
||||
/**
|
||||
\return \c true if both this and \a that use the same QuaZip
|
||||
instance and point to the same directory.
|
||||
*/
|
||||
QuaZipDir& operator=(const QuaZipDir &that);
|
||||
/// Returns the name of the entry at the specified position.
|
||||
QString operator[](int pos) const;
|
||||
/// Returns the current case sensitivity mode.
|
||||
QuaZip::CaseSensitivity caseSensitivity() const;
|
||||
/// Changes the 'current' directory.
|
||||
/**
|
||||
* If the path starts with '/', it is interpreted as an absolute
|
||||
* path from the root of the archive. Otherwise, it is interpreted
|
||||
* as a path relative to the current directory as was set by the
|
||||
* previous cd() or the constructor.
|
||||
*
|
||||
* Note that the subsequent path() call will not return a path
|
||||
* starting with '/' in all cases.
|
||||
*/
|
||||
bool cd(const QString &dirName);
|
||||
/// Goes up.
|
||||
bool cdUp();
|
||||
/// Returns the number of entries in the directory.
|
||||
uint count() const;
|
||||
/// Returns the current directory name.
|
||||
/**
|
||||
The name doesn't include the path.
|
||||
*/
|
||||
QString dirName() const;
|
||||
/// Returns the list of the entries in the directory.
|
||||
/**
|
||||
\param nameFilters The list of file patterns to list, uses the same
|
||||
syntax as QDir.
|
||||
\param filters The entry type filters, only Files and Dirs are
|
||||
accepted.
|
||||
\param sort Sorting mode (not supported yet).
|
||||
*/
|
||||
QList<QuaZipFileInfo> entryInfoList(const QStringList &nameFilters,
|
||||
QDir::Filters filters = QDir::NoFilter,
|
||||
QDir::SortFlags sort = QDir::NoSort) const;
|
||||
/// Returns the list of the entries in the directory.
|
||||
/**
|
||||
\overload
|
||||
|
||||
The same as entryInfoList(QStringList(), filters, sort).
|
||||
*/
|
||||
QList<QuaZipFileInfo> entryInfoList(QDir::Filters filters = QDir::NoFilter,
|
||||
QDir::SortFlags sort = QDir::NoSort) const;
|
||||
/// Returns the list of the entry names in the directory.
|
||||
/**
|
||||
The same as entryInfoList(nameFilters, filters, sort), but only
|
||||
returns entry names.
|
||||
*/
|
||||
QStringList entryList(const QStringList &nameFilters,
|
||||
QDir::Filters filters = QDir::NoFilter,
|
||||
QDir::SortFlags sort = QDir::NoSort) const;
|
||||
/// Returns the list of the entry names in the directory.
|
||||
/**
|
||||
\overload
|
||||
|
||||
The same as entryList(QStringList(), filters, sort).
|
||||
*/
|
||||
QStringList entryList(QDir::Filters filters = QDir::NoFilter,
|
||||
QDir::SortFlags sort = QDir::NoSort) const;
|
||||
/// Returns \c true if the entry with the specified name exists.
|
||||
/**
|
||||
The ".." is considered to exist if the current directory
|
||||
is not root. The "." and "/" are considered to
|
||||
always exist. Paths starting with "/" are relative to
|
||||
the archive root, other paths are relative to the current dir.
|
||||
*/
|
||||
bool exists(const QString &fileName) const;
|
||||
/// Return \c true if the directory pointed by this QuaZipDir exists.
|
||||
bool exists() const;
|
||||
/// Returns the full path to the specified file.
|
||||
/**
|
||||
Doesn't check if the file actually exists.
|
||||
*/
|
||||
QString filePath(const QString &fileName) const;
|
||||
/// Returns the default filter.
|
||||
QDir::Filters filter();
|
||||
/// Returns if the QuaZipDir points to the root of the archive.
|
||||
/**
|
||||
Not that the root path is the empty string, not '/'.
|
||||
*/
|
||||
bool isRoot() const;
|
||||
/// Return the default name filter.
|
||||
QStringList nameFilters() const;
|
||||
/// Returns the path to the current dir.
|
||||
/**
|
||||
The path never starts with '/', and the root path is an empty
|
||||
string.
|
||||
*/
|
||||
QString path() const;
|
||||
/// Returns the path to the specified file relative to the current dir.
|
||||
QString relativeFilePath(const QString &fileName) const;
|
||||
/// Sets the default case sensitivity mode.
|
||||
void setCaseSensitivity(QuaZip::CaseSensitivity caseSensitivity);
|
||||
/// Sets the default filter.
|
||||
void setFilter(QDir::Filters filters);
|
||||
/// Sets the default name filter.
|
||||
void setNameFilters(const QStringList &nameFilters);
|
||||
/// Goes to the specified path.
|
||||
/**
|
||||
The difference from cd() is that this function never checks if the
|
||||
path actually exists and doesn't use relative paths, so it's
|
||||
possible to go to the root directory with setPath("").
|
||||
|
||||
Note that this function still chops the trailing and/or leading
|
||||
'/' and treats a single '/' as the root path (path() will still
|
||||
return an empty string).
|
||||
*/
|
||||
void setPath(const QString &path);
|
||||
/// Sets the default sorting mode.
|
||||
void setSorting(QDir::SortFlags sort);
|
||||
/// Returns the default sorting mode.
|
||||
QDir::SortFlags sorting() const;
|
||||
};
|
||||
|
||||
#endif // QUAZIP_QUAZIPDIR_H
|
488
quazip/quazipfile.cpp
Normal file
488
quazip/quazipfile.cpp
Normal file
@ -0,0 +1,488 @@
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/// 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:
|
||||
/// 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.
|
||||
ulong 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), internal(true), zipError(UNZ_OK) {}
|
||||
/// The constructor for the corresponding QuaZipFile constructor.
|
||||
inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
|
||||
q(q), 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), internal(true), zipError(UNZ_OK)
|
||||
{
|
||||
zip=new QuaZip(zipName);
|
||||
this->fileName=fileName;
|
||||
if (this->fileName.startsWith('/'))
|
||||
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), 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('/'))
|
||||
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(q->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())
|
||||
zipClearFlags(p->zip->getZipFile(), ZIP_WRITE_DATA_DESCRIPTOR);
|
||||
p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
|
||||
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(),
|
||||
method, level, (int)raw,
|
||||
windowBits, memLevel, strategy,
|
||||
password, (uLong)crc));
|
||||
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 unztell(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_info info_z;
|
||||
p->setZipError(UNZ_OK);
|
||||
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
|
||||
p->setZipError(unzGetCurrentFileInfo(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_info info_z;
|
||||
p->setZipError(UNZ_OK);
|
||||
if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
|
||||
p->setZipError(unzGetCurrentFileInfo(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)
|
||||
{
|
||||
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(zipCloseFileInZipRaw(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();
|
||||
}
|
442
quazip/quazipfile.h
Normal file
442
quazip/quazipfile.h
Normal file
@ -0,0 +1,442 @@
|
||||
#ifndef QUA_ZIPFILE_H
|
||||
#define QUA_ZIPFILE_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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 "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.
|
||||
*
|
||||
* Returns \c false in the case of an error.
|
||||
**/
|
||||
bool getFileInfo(QuaZipFileInfo *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;
|
||||
};
|
||||
|
||||
#endif
|
66
quazip/quazipfileinfo.h
Normal file
66
quazip/quazipfileinfo.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef QUA_ZIPFILEINFO_H
|
||||
#define QUA_ZIPFILEINFO_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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 <QByteArray>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "quazip_global.h"
|
||||
|
||||
/// Information about a file inside archive.
|
||||
/** 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;
|
||||
};
|
||||
|
||||
#endif
|
51
quazip/quazipnewinfo.cpp
Normal file
51
quazip/quazipnewinfo.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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 <QFileInfo>
|
||||
|
||||
#include "quazipnewinfo.h"
|
||||
|
||||
|
||||
QuaZipNewInfo::QuaZipNewInfo(const QString& name):
|
||||
name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0)
|
||||
{
|
||||
}
|
||||
|
||||
QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file):
|
||||
name(name), internalAttr(0), externalAttr(0)
|
||||
{
|
||||
QFileInfo info(file);
|
||||
QDateTime lm = info.lastModified();
|
||||
if (!info.exists())
|
||||
dateTime = QDateTime::currentDateTime();
|
||||
else
|
||||
dateTime = lm;
|
||||
}
|
||||
|
||||
void QuaZipNewInfo::setFileDateTime(const QString& file)
|
||||
{
|
||||
QFileInfo info(file);
|
||||
QDateTime lm = info.lastModified();
|
||||
if (info.exists())
|
||||
dateTime = lm;
|
||||
}
|
102
quazip/quazipnewinfo.h
Normal file
102
quazip/quazipnewinfo.h
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef QUA_ZIPNEWINFO_H
|
||||
#define QUA_ZIPNEWINFO_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||
|
||||
This program 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 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
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 <QString>
|
||||
|
||||
#include "quazip_global.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).
|
||||
**/
|
||||
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.
|
||||
quint32 externalAttr;
|
||||
/// File comment.
|
||||
/** Will be encoded using QuaZip::getCommentCodec().
|
||||
**/
|
||||
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 and dateTime with timestamp of the
|
||||
* file named \a 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 date and time. Attributes are
|
||||
* initialized with zeros, comment and extra field with null values.
|
||||
*
|
||||
* \sa setFileDateTime()
|
||||
**/
|
||||
QuaZipNewInfo(const QString& name, const QString& file);
|
||||
/// 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);
|
||||
};
|
||||
|
||||
#endif
|
1603
quazip/unzip.c
Normal file
1603
quazip/unzip.c
Normal file
File diff suppressed because it is too large
Load Diff
356
quazip/unzip.h
Normal file
356
quazip/unzip.h
Normal file
@ -0,0 +1,356 @@
|
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
|
||||
WinZip, InfoZip tools and compatible.
|
||||
|
||||
Multi volume ZipFile (span) are not supported.
|
||||
Encryption compatible with pkzip 2.04g only supported
|
||||
Old compressions used by old PKZip 1.x are not supported
|
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com
|
||||
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
|
||||
|
||||
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.
|
||||
|
||||
Modified by Sergey A. Tachenov to integrate with Qt.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at :
|
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/
|
||||
|
||||
#ifndef _unz_H
|
||||
#define _unz_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _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)
|
||||
|
||||
/* 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_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_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));
|
||||
/*
|
||||
Open a Zip file. path contain whatever zopen_file from the IO API
|
||||
accepts. For Qt implementation it is a pointer to QIODevice, for
|
||||
fopen() implementation it's a file name.
|
||||
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.
|
||||
*/
|
||||
|
||||
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 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));
|
||||
/*
|
||||
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);
|
||||
|
||||
/* ****************************************** */
|
||||
|
||||
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)
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
/* 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));
|
||||
/*
|
||||
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 uLong ZEXPORT unzGetOffset (unzFile file);
|
||||
|
||||
/* Set the current file offset */
|
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _unz_H */
|
1281
quazip/zip.c
Normal file
1281
quazip/zip.c
Normal file
File diff suppressed because it is too large
Load Diff
245
quazip/zip.h
Normal file
245
quazip/zip.h
Normal file
@ -0,0 +1,245 @@
|
||||
/* zip.h -- IO for compress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
|
||||
WinZip, InfoZip tools and compatible.
|
||||
Multi volume ZipFile (span) are not supported.
|
||||
Encryption compatible with pkzip 2.04g only supported
|
||||
Old compressions used by old PKZip 1.x are not supported
|
||||
|
||||
For uncompress .zip file, look at unzip.h
|
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com
|
||||
Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
|
||||
|
||||
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.
|
||||
|
||||
Modified by Sergey A. Tachenov to integrate with Qt.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at :
|
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/
|
||||
|
||||
#ifndef _zip_H
|
||||
#define _zip_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _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
|
||||
|
||||
#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));
|
||||
/*
|
||||
Create a zipfile.
|
||||
file is whatever the IO API accepts. For Qt IO API it's a pointer to
|
||||
QIODevice. For fopen() IO API it's a file name (const char*).
|
||||
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 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));
|
||||
/*
|
||||
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)
|
||||
*/
|
||||
|
||||
|
||||
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));
|
||||
|
||||
/*
|
||||
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 crcForCtypting));
|
||||
|
||||
/*
|
||||
Same than zipOpenNewFileInZip2, except
|
||||
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
|
||||
password : crypting password (NULL for no crypting)
|
||||
crcForCtypting : crc of file to compress (needed for crypting)
|
||||
*/
|
||||
|
||||
|
||||
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));
|
||||
/*
|
||||
Close the current file in the zipfile, for fiel 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
|
||||
*/
|
||||
|
||||
/*
|
||||
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 /* _zip_H */
|
Loading…
Reference in New Issue
Block a user