diff --git a/Charcoal/Charcoal/AZW3.cpp b/Charcoal/Charcoal/AZW3.cpp index f592646..1cb0a34 100644 --- a/Charcoal/Charcoal/AZW3.cpp +++ b/Charcoal/Charcoal/AZW3.cpp @@ -1 +1,198 @@ #include "AZW3.h" +#include +#include +#include +#include +#include +#include +#include "stb_image.h" +#include "stb_image_write.h" +#include +#include +#include + +#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING +#include + +using namespace std; +namespace fs = std::experimental::filesystem; + +#pragma once + +std::string wstring_to_utf8(const std::wstring& wstr) { + if (wstr.empty()) return std::string(); + + int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), nullptr, 0, nullptr, nullptr); + std::string strTo(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, nullptr, nullptr); + return strTo; +} + +std::string safeCharPtrToString(const char* charPtr) { + if (charPtr != nullptr) { + return std::string(charPtr); + } + else { + return std::string(); + } +} + +MOBIData* initAndLoadMobi(const std::string& filePath) { + MOBIData* mobiData = mobi_init(); + if (!mobiData) { + std::cerr << "Memory allocation for MOBIData failed." << std::endl; + return nullptr; + } + + FILE* file; + errno_t err = fopen_s(&file, filePath.c_str(), "rb"); + if (err != 0 || file == nullptr) { + std::cerr << "Failed to open file: " << filePath << " with error code: " << err << std::endl; + mobi_free(mobiData); + return nullptr; + } + + if (mobi_load_file(mobiData, file) != MOBI_SUCCESS) { + std::cerr << "Failed to load MOBI file: " << filePath << std::endl; + fclose(file); + mobi_free(mobiData); + return nullptr; + } + + fclose(file); + return mobiData; +} + +book azw3::add(PWSTR path) { + // Convert PWSTR to std::wstring + std::wstring ws(path); + // Now convert std::wstring to std::string + std::string filePath = wstring_to_utf8(ws); + + // Initialize and load MOBI file + MOBIData* mobiData = initAndLoadMobi(filePath); + if (!mobiData) { + // Handle error: unable to initialize and load MOBI + std::cerr << "Unable to initialize and load MOBI data" << std::endl; + return book(); // Return an empty book object + } + + book curr; + // Extract metadata + curr.title = mobi_meta_get_title(mobiData); + curr.author = safeCharPtrToString(mobi_meta_get_author(mobiData)); + curr.publisher = safeCharPtrToString(mobi_meta_get_publisher(mobiData)); + curr.contributor = safeCharPtrToString(mobi_meta_get_contributor(mobiData)); + curr.rights = safeCharPtrToString(mobi_meta_get_copyright(mobiData)); + curr.format = "AZW3"; + curr.date = safeCharPtrToString(mobi_meta_get_publishdate(mobiData)); + curr.language = safeCharPtrToString(mobi_meta_get_language(mobiData)); + curr.description = safeCharPtrToString(mobi_meta_get_description(mobiData)); + + mobi_free(mobiData); + + return curr; +} + +book mobi::add(PWSTR path) { + std::wstring ws(path); + std::string filePath = wstring_to_utf8(ws); + + // Initialize and load MOBI file + MOBIData* mobiData = initAndLoadMobi(filePath); + if (!mobiData) { + // Handle error: unable to initialize and load MOBI + std::cerr << "Unable to initialize and load MOBI data" << std::endl; + return book(); // Return an empty book object + } + + book curr; + // Extract metadata + curr.title = mobi_meta_get_title(mobiData); + curr.author = safeCharPtrToString(mobi_meta_get_author(mobiData)); + curr.publisher = safeCharPtrToString(mobi_meta_get_publisher(mobiData)); + curr.contributor = safeCharPtrToString(mobi_meta_get_contributor(mobiData)); + curr.rights = safeCharPtrToString(mobi_meta_get_copyright(mobiData)); + curr.format = "MOBI"; + curr.date = safeCharPtrToString(mobi_meta_get_publishdate(mobiData)); + curr.language = safeCharPtrToString(mobi_meta_get_language(mobiData)); + curr.description = safeCharPtrToString(mobi_meta_get_description(mobiData)); + + mobi_free(mobiData); + + return curr; +} + +void extractTextAndOtherContent(const MOBIRawml* rawml, const std::string& outputDir) { + for (MOBIPart* part = rawml->markup; part != NULL; part = part->next) { + if (part->type == T_HTML) { + std::string filename = outputDir + "/markup_" + std::to_string(part->uid) + ".html"; + std::ofstream outFile(filename, std::ios::binary); + outFile.write(reinterpret_cast(part->data), part->size); + outFile.close(); + } + } +} + +void extractImages(const MOBIRawml* rawml, const std::string& outputDir, int scaleFactor) { + for (MOBIPart* part = rawml->resources; part != NULL; part = part->next) { + if (part->type == T_JPG || part->type == T_PNG || part->type == T_GIF || part->type == T_BMP) { + std::string extension; + switch (part->type) { + case T_JPG: extension = ".jpg"; break; + case T_PNG: extension = ".png"; break; + case T_GIF: extension = ".gif"; break; + case T_BMP: extension = ".bmp"; break; + default: continue; + } + + int width, height, channels; + unsigned char* imgData = stbi_load_from_memory(part->data, part->size, &width, &height, &channels, 0); + if (imgData) { + // Convert the image to grayscale using OpenCV + cv::Mat colorImg(height, width, channels == 4 ? CV_8UC4 : channels == 3 ? CV_8UC3 : CV_8UC1, imgData); + cv::Mat grayImg; + cv::cvtColor(colorImg, grayImg, cv::COLOR_BGR2GRAY); + + // Optionally resize the image according to scaleFactor + if (scaleFactor != 1) { + cv::resize(grayImg, grayImg, cv::Size(), scaleFactor, scaleFactor, cv::INTER_LINEAR); + } + + // Save the grayscale image + std::string filename = outputDir + "/image_" + std::to_string(part->uid) + extension; + cv::imwrite(filename, grayImg); + + // Free the image data allocated by stb_image + stbi_image_free(imgData); + } + else { + std::cerr << "Failed to load image for grayscaling from memory." << std::endl; + } + } + } +} + +bool extractContentFromMobi(const std::string& filePath, const std::string& outputDir, int scaleFactor) { + MOBIData* mobiData = initAndLoadMobi(filePath); + if (!mobiData) return false; + + if (!fs::create_directories(outputDir) && !fs::exists(outputDir)) { + std::cerr << "Failed to create output directory: " << outputDir << std::endl; + mobi_free(mobiData); + return false; + } + + MOBIRawml* rawml = mobi_init_rawml(mobiData); + if (!rawml || mobi_parse_rawml(rawml, mobiData) != MOBI_SUCCESS) { + std::cerr << "Failed to initialize or parse MOBI rawml" << std::endl; + mobi_free(mobiData); // Clean up mobiData + return false; + } + + // Clean up + mobi_free_rawml(rawml); + mobi_free(mobiData); + + return true; +} \ No newline at end of file diff --git a/Charcoal/Charcoal/AZW3.h b/Charcoal/Charcoal/AZW3.h index e6ef753..3c3add1 100644 --- a/Charcoal/Charcoal/AZW3.h +++ b/Charcoal/Charcoal/AZW3.h @@ -1,6 +1,29 @@ #pragma once #include "Library.h" -class AZW3 : public Library +#include "mobi.h" +#include +#include + +std::string wstring_to_utf8(const std::wstring& wstr); + +class mobi : public Library +{ + public: + book add(PWSTR path); +}; + +class azw3 : public Library { +public: + book add(PWSTR path); }; +//Utility functions that are used across different files +std::string wstring_to_utf8(const std::wstring& wstr); +std::string safeCharPtrToString(const char* charPtr); + +//Function declarations related to MOBI library handling +MOBIData* initAndLoadMobi(const std::string& filePath); +void extractTextAndOtherContent(const MOBIRawml* rawml, const std::string& outputDir); +void extractImages(const MOBIRawml* rawml, const std::string& outputDir, int scaleFactor); +bool extractContentFromMobi(const std::string& filePath, const std::string& outputDir, int scaleFactor); \ No newline at end of file diff --git a/Charcoal/Charcoal/Charcoal.vcxproj b/Charcoal/Charcoal/Charcoal.vcxproj index bd32852..e0b0894 100644 --- a/Charcoal/Charcoal/Charcoal.vcxproj +++ b/Charcoal/Charcoal/Charcoal.vcxproj @@ -108,14 +108,14 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(SolutionDir)Charcoal\openvc-4.9.0\include;$(SolutionDir)Charcoal\ultralight-sdk\include;$(SolutionDir)Charcoal\libepub-master\include + $(SolutionDir)Charcoal\libmobi-public\src;$(SolutionDir)Charcoal\packages\libxml2-vc140-static-32_64.2.9.4.1\lib\native\include\libxml;$(SolutionDir)Charcoal\openvc-4.9.0\include;$(SolutionDir)Charcoal\ultralight-sdk\include;$(SolutionDir)Charcoal\libepub-master\include stdcpp17 Windows true - AppCore.lib;Ultralight.lib;UltralightCore.lib;WebCore.lib;%(AdditionalDependencies) - $(SolutionDir)Charcoal\ultralight-sdk\lib + AppCore.lib;Ultralight.lib;UltralightCore.lib;WebCore.lib;libmobi.lib;libxml2.lib;Ws2_32.lib;%(AdditionalDependencies) + $(SolutionDir)Charcoal\libmobi-public\msvc\x64\Debug;$(SolutionDir)Charcoal\packages\libxml2-vc140-static-32_64.2.9.4.1\lib\native\libs\x64\static\Debug;$(SolutionDir)Charcoal\ultralight-sdk\lib mainCRTStartup diff --git a/Charcoal/Charcoal/Library.cpp b/Charcoal/Charcoal/Library.cpp index f5b42e5..a1756e6 100644 --- a/Charcoal/Charcoal/Library.cpp +++ b/Charcoal/Charcoal/Library.cpp @@ -96,11 +96,18 @@ std::string Library::add(PWSTR path) } else if (f == "AZW3" || f == "azw3") { - /* AZW3 a; + azw3 a; book curr = a.add(path); collection.push_back(curr); - return curr.title;*/ + return curr.title; } + else if (f == "MOBI" || f == "mobi") + { + mobi m; + book curr = m.add(path); + collection.push_back(curr); + return curr.title; + } else if (f == "pdf" || f == "PDF") { /*PDF p; diff --git a/Charcoal/Charcoal/libmobi-public/.github/workflows/build.yml b/Charcoal/Charcoal/libmobi-public/.github/workflows/build.yml new file mode 100644 index 0000000..d5fffd8 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/.github/workflows/build.yml @@ -0,0 +1,101 @@ +name: Build + +on: + push: + branches: [ public ] + pull_request: + branches: [ public ] + +jobs: + unix-build: + + runs-on: ubuntu-latest + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + config: + - name: default build with debug + options: --enable-debug + - name: bulid with internal libs + options: --with-zlib=no --with-libxml2=no + - name: build without encryption + options: --disable-encryption + + steps: + - uses: actions/checkout@v2 + - name: install dependencies + run: | + if [ "${{ runner.os }}" = "Linux" ]; then + sudo apt-get update -qq; + sudo apt-get install -y autotools-dev pkg-config automake autoconf libtool; + sudo apt-get install -y zlib1g-dev libxml2-dev; + elif [ "${{ runner.os }}" = "macOS" ]; then + brew update > /dev/null; + brew outdated autoconf || brew upgrade autoconf; + brew outdated automake || brew upgrade automake; + brew outdated libtool || brew upgrade libtool; + fi + - name: autogen + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.config.options }} + - name: make + run: make -j `nproc` + - name: make check + run: make -j `nproc` check + - name: make distcheck + run: make -j `nproc` distcheck + - name: upload debug artifacts + uses: actions/upload-artifact@v2 + if: ${{ failure() }} + with: + name: test-logs + path: | + **/tests/test-suite.log + **/tests/samples/*.log + + win64-build: + + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + steps: + - name: setup-msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + path-type: minimal + update: true + install: >- + git + autotools + base-devel + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-libtool + mingw-w64-x86_64-libxml2 + mingw-w64-x86_64-zlib + - name: checkout + uses: actions/checkout@v2 + - name: autogen + run: sh ./autogen.sh + - name: configure + run: ./configure --enable-debug + - name: make + run: make -j$(nproc) + - name: make check + run: make -j$(nproc) check + - name: make distcheck + run: make -j$(nproc) distcheck + - name: upload debug artifacts + uses: actions/upload-artifact@v2 + if: ${{ failure() }} + with: + name: test-logs + path: | + **/tests/test-suite.log + **/tests/samples/*.log diff --git a/Charcoal/Charcoal/libmobi-public/.github/workflows/codeql-analysis.yml b/Charcoal/Charcoal/libmobi-public/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..5367c0a --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ public ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ public ] + schedule: + - cron: '19 13 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/Charcoal/Charcoal/libmobi-public/.github/workflows/coverity-scan.yml b/Charcoal/Charcoal/libmobi-public/.github/workflows/coverity-scan.yml new file mode 100644 index 0000000..f47da3f --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/.github/workflows/coverity-scan.yml @@ -0,0 +1,54 @@ +name: coverity-scan + +on: + push: + branches: [ public ] + +jobs: + coverity-build: + + runs-on: ubuntu-latest + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: install dependencies + run: | + sudo apt-get update -qq; + sudo apt-get install -y autotools-dev pkg-config automake autoconf libtool; + sudo apt-get install -y zlib1g-dev libxml2-dev; + - name: download coverity tools + run: | + curl -Lf \ + -o cov-analysis-linux64.tar.gz \ + --form project=bfabiszewski/libmobi \ + --form token=$TOKEN \ + https://scan.coverity.com/download/linux64 + mkdir cov-analysis-linux64 + tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 + env: + TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} + - name: autogen + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.config.options }} + - name: build with cov-build + run: | + export PATH=`pwd`/cov-analysis-linux64/bin:$PATH + cov-build --dir cov-int make -j `nproc` + - name: upload results to coverity-scan + run: | + tar czvf cov-int.tgz cov-int + curl -Lf \ + --form token=$TOKEN \ + --form email=scan.coverity@fabiszewski.net \ + --form file=@cov-int.tgz \ + --form version="`git describe --tags`" \ + --form description="libmobi `git describe --tags`" \ + "https://scan.coverity.com/builds?project=bfabiszewski/libmobi" + env: + TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} diff --git a/Charcoal/Charcoal/libmobi-public/.travis.yml b/Charcoal/Charcoal/libmobi-public/.travis.yml new file mode 100644 index 0000000..05e71aa --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/.travis.yml @@ -0,0 +1,39 @@ +os: +- linux +# - osx +language: c +compiler: +- clang +- gcc +before_install: +- if [ "$TRAVIS_OS_NAME" == "linux" ]; then + sudo apt-get update -qq; + sudo apt-get install -y autotools-dev pkg-config automake autoconf libtool; + sudo apt-get install -y zlib1g-dev libxml2-dev; + elif [ "$TRAVIS_OS_NAME" == "osx" ]; then + brew update > /dev/null; + brew outdated autoconf || brew upgrade autoconf; + brew outdated automake || brew upgrade automake; + brew outdated libtool || brew upgrade libtool; + fi +- git config --global user.name "Travis CI (libmobi)" +- git config --global user.email $HOSTNAME":not-for-mail@travis-ci.org" +script: +- ./autogen.sh +- ./configure --enable-debug && make && make test +- make clean +- ./configure --with-zlib=no --with-libxml2=no && make && make test + +env: + global: + - secure: "ShIL3IDvH59cJx4QAKWhVTs7ynCAfID11DqK8pIWJX2UtvXc4pdDQUq6U5ZRLUT0BR6kmLNxYrQUpUKvZ9sYnPuj4X5o9jzXzXsJPXTy/qpjiLK4MCZLIlI4OAHexfAuZTOVZHOoE/B8ABpk8nGYUXk02++LxlmwtE/fIWOOWHs=" + +addons: + coverity_scan: + project: + name: "bfabiszewski/libmobi" + description: "Build submitted via Travis CI" + notification_email: scan.coverity@fabiszewski.net + build_command_prepend: "./autogen.sh && ./configure" + build_command: "make -j 4" + branch_pattern: public diff --git a/Charcoal/Charcoal/libmobi-public/AUTHORS b/Charcoal/Charcoal/libmobi-public/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/Charcoal/Charcoal/libmobi-public/CMakeLists.txt b/Charcoal/Charcoal/libmobi-public/CMakeLists.txt new file mode 100644 index 0000000..9e98dd6 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/CMakeLists.txt @@ -0,0 +1,118 @@ +# Copyright (c) 2022 Bartek Fabiszewski +# http://www.fabiszewski.net +# +# This file is part of libmobi. +# Licensed under LGPL, either version 3, or any later. +# See + +cmake_minimum_required(VERSION 3.12) + +project(LIBMOBI C) + +set(CMAKE_C_STANDARD 99) + +file(STRINGS ${LIBMOBI_SOURCE_DIR}/configure.ac VERSION_LINE REGEX "AC_INIT\\(\\[libmobi\\], \\[(.*)\\]\\)") +string(REGEX MATCH "([0-9]+\\.[0-9]+)" PACKAGE_VERSION "${VERSION_LINE}") +message(STATUS "libmobi version ${PACKAGE_VERSION}") +add_definitions(-DPACKAGE_VERSION="${PACKAGE_VERSION}") +string(REPLACE "." ";" VERSION_LIST ${PACKAGE_VERSION}) +list(GET VERSION_LIST 0 PACKAGE_VERSION_MAJOR) +list(GET VERSION_LIST 1 PACKAGE_VERSION_MINOR) + +# Option to enable encryption +option(USE_ENCRYPTION "Enable encryption" ON) + +# Option to enable static tools compilation +option(TOOLS_STATIC "Enable static tools compilation" OFF) + +# Option to use libxml2 +option(USE_LIBXML2 "Use libxml2 instead of internal xmlwriter" ON) + +# Option to use zlib +option(USE_ZLIB "Use zlib" ON) + +# Option to enable XMLWRITER +option(USE_XMLWRITER "Enable xmlwriter (for opf support)" ON) + +# Option to enable debug +option(MOBI_DEBUG "Enable debug" OFF) + +# Option to enable debug alloc +option(MOBI_DEBUG_ALLOC "Enable debug alloc" OFF) + +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) + +if(TOOLS_STATIC) + set(BUILD_SHARED_LIBS OFF) +endif(TOOLS_STATIC) + +if(USE_ENCRYPTION) + add_definitions(-DUSE_ENCRYPTION) +endif(USE_ENCRYPTION) + +if(USE_XMLWRITER) + add_definitions(-DUSE_XMLWRITER) + if(USE_LIBXML2) + add_definitions(-DUSE_LIBXML2) + find_package(LibXml2 REQUIRED) + include_directories(${LIBXML2_INCLUDE_DIR}) + endif(USE_LIBXML2) +endif(USE_XMLWRITER) + +if(MOBI_DEBUG) + add_definitions(-DMOBI_DEBUG) + message(STATUS "CMAKE_CXX_COMPILER_ID=${CMAKE_C_COMPILER_ID}") + if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU") + add_compile_options(-pedantic -Wall -Wextra -Werror) + endif() +endif(MOBI_DEBUG) + +if(MOBI_DEBUG_ALLOC) + add_definitions(-DMOBI_DEBUG_ALLOC) +endif(MOBI_DEBUG_ALLOC) + +if(USE_ZLIB) + find_package(ZLIB REQUIRED) + include_directories(${ZLIB_INCLUDE_DIR}) +else() + add_definitions(-DUSE_MINIZ) +endif(USE_ZLIB) + +include(CheckIncludeFile) +include(CheckFunctionExists) +check_include_file(unistd.h HAVE_UNISTD_H) +if(HAVE_UNISTD_H) + add_definitions(-DHAVE_UNISTD_H) +endif(HAVE_UNISTD_H) +check_function_exists(getopt HAVE_GETOPT) +if(HAVE_GETOPT) + add_definitions(-DHAVE_GETOPT) +endif(HAVE_GETOPT) + +check_function_exists(strdup HAVE_STRDUP) +if(HAVE_STRDUP) + add_definitions(-DHAVE_STRDUP) +endif(HAVE_STRDUP) + +check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) +if(HAVE_SYS_RESOURCE_H) + add_definitions(-DHAVE_SYS_RESOURCE_H) +endif(HAVE_SYS_RESOURCE_H) + + +include(CheckCSourceCompiles) +foreach(keyword "inline" "__inline__" "__inline") + check_c_source_compiles("${keyword} void func(); void func() { } int main() { func(); return 0; }" HAVE_INLINE) + if(HAVE_INLINE) + add_definitions(-DMOBI_INLINE=${keyword}) + break() + endif(HAVE_INLINE) +endforeach(keyword) + +check_c_source_compiles("void func() { } __attribute__((noreturn)); int main() { func(); return 0; }" HAVE_ATTRIBUTE_NORETURN) +if(HAVE_ATTRIBUTE_NORETURN) + add_definitions(-DHAVE_ATTRIBUTE_NORETURN) +endif(HAVE_ATTRIBUTE_NORETURN) + +add_subdirectory(src) +add_subdirectory(tools) diff --git a/Charcoal/Charcoal/libmobi-public/COPYING b/Charcoal/Charcoal/libmobi-public/COPYING new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/Charcoal/Charcoal/libmobi-public/ChangeLog b/Charcoal/Charcoal/libmobi-public/ChangeLog new file mode 100644 index 0000000..aecdd4a --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/ChangeLog @@ -0,0 +1,367 @@ +2024-02-04: Fix: missing header with libxml2 >= 2.12 +2024-02-04: Max index count value is too low for some dictionaries +2023-08-10: Fix CMake debug build with MSVC, fixes #46 +2023-07-11: Clean up unused value +2023-07-11: Fix clang warning about missing function prototypes (-Wstrict-prototypes) +2023-02-21: Update Xcode project settings +2023-02-21: Replace deprecated functions +2023-02-21: Try to reconstruct sources even on broken indices +2023-02-05: Refactor mobi_buffer_get_varlen_internal to be compatible with other buffer functions. Update documentation with information about mobi_buffer_get_varlen_dec limitation. +2022-06-26: Fix undefined behavior with null pointer arithmetics in case of corrupt input +2022-05-28: Version 0.11 +2022-05-27: Fix potential null pointer dereference on corrupt input when inflections CNCX record is not initialized +2022-05-23: Fix index entries count +2022-05-23: Prevent leak of index entries on corrupt data +2022-05-23: Add checks for fragments part in case of corrupt data +2022-05-17: Fix potential integer overflow with corrupt data +2022-05-05: Fix: index entry label not being zero-terminated with corrupt input +2022-05-03: Fix boundary checking error in markup search, that could cause buffer over-read with corrupt input +2022-05-02: Fix typo in macro name +2022-04-27: Fix undefined behavior when passing null to strdup +2022-04-27: Fix wrong boundary checks in inflections parser resulting in stack buffer over-read with corrupt input +2022-04-26: Fix text formatting +2022-04-26: Fix array boundary check when parsing inflections which could result in buffer over-read with corrupt input +2022-04-23: Fix formatting +2022-04-23: Fix checking boundary of deobfuscation key which could cause buffer over-read with corrupt data +2022-04-23: Fix issue with corrupt data with empty lookup string which could lead to read beyond buffer +2022-04-23: Fix faulty checks for array boundary which caused buffer over-read with corrupt input +2022-04-23: Fix issue with corrupt files with tagvalues_count = 0 that caused null pointer dereference +2022-04-23: Fix issues when mobi_buffer_getpointer returns null. With corrupt data this could lead to out-of-bounds read +2022-04-13: Add packaging status [skip ci] +2022-04-10: Make random generation return proper error codes +2022-04-10: Rewrite randombytes for libmobi +2022-04-07: Add libsodium randombytes.c +2022-04-10: Fix "fallthrough" spelling +2022-04-10: Make declaration match definition +2022-04-10: Fix different sign comparison warning +2022-04-10: Update Xcode project +2022-04-10: Don't run tests if bash is missing +2022-04-10: Looking for libxml2, first try pkg-config +2022-04-04: Update MSVC project +2022-04-02: Add support for GNU/kFreeBSD and GNU/Hurd +2022-04-02: Check for inline, noreturn support in CMake +2022-03-27: Fix format truncation warning +2022-03-21: Version 0.10 +2022-03-21: Update Xcode project [skip ci] +2022-03-21: Add functions for retrieving orthographic index entries +2022-02-27: Add basic CMake support +2022-02-26: GHA: fetch tags with checkout +2022-02-26: Minor refactoring of file path manipulation function +2022-02-26: Fix memory handling issues +2022-02-26: Add coverity scan workflow +2022-02-25: Remove obsolete changelog +2022-02-25: Fix md5sum output on Windows +2022-02-25: Fix inconsistent separators in path on Windows builds +2022-02-25: GHA: fix log paths +2022-02-25: GHA: fix workflow syntax +2022-02-25: GHA: upload test logs on failure +2022-02-24: Fix printf format specifier +2022-02-24: Fix sample path in Makefile +2022-02-24: Missing autotools in mingw workflow +2022-02-24: Windows doesn't accept asterisk in file names +2022-02-24: Update workflow, add badge +2022-02-24: Add mingw workflow +2022-02-24: Fix tests in out-of-tree build +2022-02-24: Update man pages +2022-02-24: Replace non-portable strptime +2022-02-24: Make sure both validity period dates are set +2022-02-21: Fix strptime not found on linux build +2022-02-21: Add build github action +2022-02-21: Update README +2022-02-21: Minor code cleanups +2022-02-21: Unify boolean and static usage in tools +2022-02-21: mobimeta: fix null pointer dereference when parsing malformed option +2022-02-18: Add hybrid spit option to mobitool +2022-02-18: Update documentation +2022-02-18: Test both encrypted hybrid parts +2022-02-18: Fix: fast decryption routine fails for non-huffman compression +2022-02-18: Fix mobitool serial decryption +2022-02-18: Add DRM tests +2022-02-17: Fix build with encryption disabled +2022-02-17: Update tests samples +2022-02-16: Add -h option to tools, update man pages +2022-02-16: Update Xcode settings +2022-02-16: Restructure, cleanup encryption related code, add mobidrm tool +2021-11-19: Improve getopt loop, fix config.h to be accessible from all tools +2021-11-10: Update xcode project +2021-11-10: Add functions to split hybrid files +2021-11-10: Avoid modifying existing records, as caller may keep reference to them +2021-11-05: Fix: tests fail if pid contains asterisk +2021-11-05: Fix: decryption may fail for some records with standard compression +2021-11-05: Replace test samples with self-generated smaller ones +2021-11-05: Skip test in case of missing checksums +2021-10-20: Version 0.9 +2021-10-24: Fix out-of-tree build +2021-10-22: Fix mingw build, code formatting +2021-10-14: Fix gcc format truncation warning +2021-10-14: Include autogen.sh in distribution bundle +2021-10-14: Create codeql-analysis.yml +2021-10-14: Fix autoconf 2.70 warnings, clean up +2021-10-14: Build fails with autoconf 2.70 +2021-10-11: Version 0.8 +2021-10-11: Update Xcode project +2021-10-11: Fix warnings about changed signedness +2021-09-18: Fix potential out-of-buffer read while parsing corrupt file, closes #38 +2021-09-18: Fix potential out-of-buffer read while parsing corrupt file, closes #35, #36 +2021-09-09: Version 0.7 +2021-09-09: fix oob write bug inside libmobi +2021-06-07: Add reference to brew formula +2020-09-02: Fix null pointer dereference in case of broken fragment +2020-08-01: Update changelog +2020-08-01: Version 0.6 +2020-07-31: Fix typo +2020-07-31: Add Readme to dist package +2020-07-31: Remove anchor on truncated link +2020-07-31: Fix missing option in man page +2020-07-30: Include test samples in dist package +2020-07-25: Fix gcc 7+ warnings about implicit fall through and format truncation +2020-07-24: Unique names for internal functions to avoid confilicts with static linking +2020-06-24: Close file in error branch +2020-06-24: Fix static compilation with miniz on gcc +2020-06-24: Minor documentation fixes +2020-06-23: Version 0.5 +2020-06-23: mobitool: add dump cover option +2020-06-23: Minor documentation improvement +2020-06-23: Fix potential buffer over-read +2019-03-18: Fix: try also "name" attribute when searching for link anchor tags, closes #24 +2019-02-22: Add mobi_is_replica function +2019-02-22: Fix potential read beyond buffer +2019-02-22: Travis migration +2018-08-07: Fix: missing items in recreated ncx file +2018-06-20: Fix: printf format warning on some gcc versions +2018-06-20: Fix: make dist broken by nonexistent header files +2018-06-20: VERSION 0.4 +2018-06-20: Fix: buffer overflow (CVE-2018-11726) +2018-06-20: Fix: buffer overflow (CVE-2018-11724) +2018-06-20: Fix: read beyond buffer (CVE-2018-11725) +2018-06-20: Fix: buffer overflow (mobitool), closes #18 +2018-06-20: Fix: read beyond buffer with corrupted KF8 Boundary record, closes #19 +2018-06-20: Fix: read beyond buffer, closes #16, #17 +2018-06-20: Updated xcode project files +2018-04-03: Fix: ncx part was not scanned for links, fixes #12 +2018-04-02: Fix regression, potential use after free +2018-04-02: Skip broken resources, fixes #10 +2018-03-05: Allow processing zero length text records, fixes #9 +2017-12-25: Skip broken first resource offset instead of dying +2017-12-18: Skip broken links reconstruction instead of dying +2017-11-27: Disable travis OS X builds, as they usually time out +2017-11-16: Fix: increase max number of dictionary entries per record +2017-11-14: Fix for some encrypted documents with palmdoc encoding +2017-11-06: Fix: potential null pointer dereference +2017-10-16: Manpage cleanup +2017-09-27: Update README +2017-09-26: Increase maximum length of attribute name and value, closes #5 +2017-02-26: Remove obsolete files from VS build (closes #3) [ci skip] +2016-11-05: Mobitool: use epub extension if extracted source resource is epub +2016-06-10: Update docs +2016-06-10: Update test files +2016-06-10: Fix: out of bounds read in corrupt font resource +2016-06-10: Prevent memory leak in case of corrupt font resources +2016-06-10: Calculate deobfuscation buffer limit from key length +2016-06-10: Fix: USE_LIBXML2 macro was not included from config.h +2016-06-10: Fix: USE_LIBXML2 macro was not included from config.h +2016-06-09: Fix: memory leak in tools +2016-06-09: Fix: potential out of bounds read +2016-06-09: Fix: memory leak in internal xmlwriter +2016-06-01: Update README +2016-05-19: Feature: verify decryption key type +2016-05-19: Cleanup converting little endian buffer to 32-bit integer +2016-05-19: Feature: check drm expiration dates +2016-05-18: Fix: memory leaks in encryption +2016-05-18: Fix concurrent autotools builds +2016-05-18: use relative path, as $(top_srcdir) fails to be substituted (?) +2016-05-18: update vcxproj +2016-05-18: Include headers in automake sources +2016-05-18: Fix: automake out-of-tree miniz build +2016-05-18: Fix: wrongly detected fdst record broke some ancient documents +2016-05-18: Fix: improve index header parsing, some old dictionaries might not load +2016-05-18: Fix: convert encoding of opf strings from cp1252 indices +2016-05-18: Quiet warnings about unused values of wiped variables +2016-05-18: Fix: potential memory leak +2016-05-18: Fix: wrongly decoded "©" entity +2016-05-16: Fix: huffdic decompression fails in case of huge documents +2016-05-14: Simplify buffer_init_null() function +2016-05-14: Use ARRAYSIZE macro +2016-05-14: Feature: calculate pid for decryption from device serial number +2016-04-29: Use endian-independent byte swapping +2016-04-29: Exclude unused miniz functions from binary +2016-04-29: Add SHA-1 routines +2016-04-27: Fix miniz.c formatting +2016-04-27: Documentation +2016-04-20: Update changelog +2016-04-20: Fix potential null pointer dereference +2016-04-20: Remove useless check +2016-04-20: Fix text record size calculation +2016-04-20: Fix buffer checking and freeing +2016-04-19: Update docs +2016-04-19: Update ChangeLog +2016-04-19: Fix comparison between signed and unsigned integer +2016-04-19: use strdup on linux/glibc +2016-04-19: Add initial write and metadata editing support. Add mobimeta tool. +2016-04-19: Always check whether memory allocation succeeded +2016-04-18: Fix: guarantee array resize step is at least 1 +2016-04-13: Workaround to read some old mobipocket files +2016-04-13: Improve pdb dates resolving +2016-04-07: Minor documentation edit +2016-04-07: Update changelog +2016-04-06: Fix format warning +2016-04-06: Update test checksums +2016-04-06: Fix: "event" attribute needs "opf" namespace +2016-04-06: Fix: id attributes in ncx file should be unique +2016-04-06: Store full name in MOBIMobiHeader structure +2016-04-05: Fix formatting +2016-04-05: Fix signedness warning +2016-04-04: Fix potential buffer overflow, closes #2 +2016-04-04: Fix potential null pointer dereference +2016-03-23: Fix signedness warnings +2016-03-22: Fix: _mkdir needs direct.h on MinGW +2016-03-22: Fix tests on Windows +2016-03-22: Fix: palmdoc decompression may fail with zero byte in input buffer +2016-03-21: VERSION 03: internal xmlwriter, metadata handling functions, bug fixes +2016-03-21: Feature: add helper functions for metadata extraction +2016-03-21: Load also kf8 data when only kf7 version is requested +2016-03-21: Fix: wrong exth header length check could discard some valid headers +2016-03-20: Get rid of extended attributes in release archive on OS X +2016-03-19: Mobitool: add descriptive error messages based on libmobi return codes +2016-03-04: Add extra length check for CMET record extraction +2016-03-04: Always check buffer allocation result +2016-03-04: Add functions to extract conversion source and log, also add this feature to mobitool +2016-03-04: Remove some stray printfs +2016-03-03: Remove not used AC_FUNC_MALLOC/REALLOC macros that break cross-compilation +2016-03-03: Fix potential illegal memory access in miniz.c +2016-03-03: Fix potential dereference of null pointer in miniz.c +2016-03-03: Fix for Android bionic libc bug (SIZE_MAX missing in stdint.h) +2016-03-03: Fix mobitool compilation on MSVC++ +2016-03-03: Add EPUB creation feature to mobitool +2016-03-02: Fix potential buffer overflow, null pointer dereference +2016-03-02: Add travis test for no-external-dependency build +2016-03-02: Fix missing strdup on linux +2016-03-02: Add internal xmlwriter (as an alternative to libxml2) +2016-03-01: Feature: decode html entities in exth header strings +2016-02-29: Fix: potential buffer overflow +2016-02-29: Fix: wrong pid calculation (regression introduced in 0.2) +2016-02-26: VERSION 0.2: increased stability, lots of bugs fixed +2016-02-26: Add Xcode project file +2016-02-26: Preliminary support for MSVC++ compiler +2016-02-26: Do not use variable length arrays +2016-02-26: Refactor mobi_reconstruct_parts() to use MOBIFragment list +2016-02-26: Fix compiler warning about sign conversion +2016-02-26: Fix compiler warning about type conversion +2016-02-26: Check the result of malloc/calloc +2016-02-26: Fix inconsistent use of const between some definitions and declarations +2016-02-24: Fix inconsistence between function declaration and definition +2016-02-24: Fix various potential crashes in case of corrupt input (afl-fuzz) +2016-02-24: Fix dead code warnings in miniz +2015-11-26: Export mobi_get_first_resource_record() function +2015-11-26: Fix: double free on corrupt cdic +2015-11-02: Update docs +2015-11-02: Feature: add helper functions to find resources by flow id +2015-11-02: Feature: export MOBI_NOTSET macro +2015-11-02: Feature: give more options to parse rawml function +2015-10-24: Restore travis.yml +2015-10-24: Fix OSX travis build +2015-10-24: Fix OSX travis build +2015-10-24: Fix multiline inline script +2015-10-24: Enable multi-OS feature +2015-10-24: Fix: unique temporary name for parallel tests +2015-10-24: Fix: decoding video resources falsely reported as failed +2015-10-24: Fix: tests, some md5sum implementations insert double spaces +2015-10-24: Fix for automake < 1.13 +2015-10-23: Add simple tests framework +2015-10-23: Fix: increase max index entries per record count, as some rare samples fail +2015-10-22: Fix: incorrectly decoded video/audio resources +2015-10-22: Feature: add option to specify output path +2015-10-14: Add some internal functions to public API: mobi_get_flow_by_uid, mobi_get_resource_by_uid, mobi_get_part_by_uid, mobi_get_exthrecord_by_tag +2015-06-13: update changelog +2015-06-13: fix: various invalid memory access +2015-06-13: don't quit on invalid input, instead substitute with replacement character +2015-06-12: fix typo +2015-06-12: update changelog +2015-06-12: fix: reconstruction failed when there were gaps between fragments +2015-06-12: add EXTH tags +2015-06-12: prevent return of garbage value check return value in case of failed malloc +2015-06-12: fix invalid memory access +2015-04-12: Fix reconstruction of "kindle:embed" links without mime type (regression) +2015-04-12: Add sanity checks to link reconstruction functions, allow skipping some malformed patterns +2015-04-12: Fix infinite loop in guide build while unknown tag was found +2015-04-12: Increase max recursion level for huffman decompression +2015-03-28: update docs +2015-03-28: fix solaris studio compiler warnings +2015-03-28: fix solaris studio compiler build +2015-02-18: Fix "more than one: -compatibility_version specified" error on powerpc +2014-11-24: improve docs +2014-11-24: simplify public header +2014-11-21: changelog update [ci skip] +2014-11-21: README +2014-11-21: fix: add sanity checks +2014-11-21: Fix: add sanity checks +2014-11-21: add sanity check to huffcdic indices count +2014-11-21: fix number of leaks and other minor issues (by coverity scan) +2014-11-20: missing notification email kills coverity scan +2014-11-20: update travis.yml +2014-11-20: upgrade travis.ml with covert scan +2014-11-20: update README.md +2014-11-20: add .travis.yml +2014-11-20: update REAME.md +2014-11-20: update README.md +2014-11-20: update docs +2014-11-20: feature: add decryption support +2014-11-20: mkdir cleanup +2014-11-17: documentation +2014-11-17: strip unneeded tags +2014-11-16: fix: potential leak +2014-11-16: fix: regression, some image tags were not reconstructed +2014-11-16: fix: improve ligatures handling +2014-11-16: override darwin linker default versioning +2014-11-15: fix: get proper LIGT entries count from index header +2014-11-15: feature: unpack records into new folder +2014-11-14: make README readable on github +2014-11-14: add README for mobitool +2014-11-14: fix: dictionaries with large inflection rules failed +2014-11-14: feature: support encoded ligatures in index entry labels +2014-11-14: readme +2014-11-14: update changelog +2014-11-13: feature: support for older inflections scheme +2014-11-13: bug: files with short tagx header won't open +2014-11-13: cleanup unneeded include +2014-11-13: use strdup on linux/glibc +2014-11-13: debugging cleanup +2014-11-13: reorganize source files +2014-11-13: use strdup on linux/glibc +2014-11-11: update changelog +2014-11-11: update changeling +2014-11-11: fix: documents with text record size > 4096 failed to load +2014-11-11: add: function to decode flat index entries +2014-11-11: debug: add functions for debugging indices +2014-11-11: cleanup +2014-11-11: fix: variable length value wrongly calculated when going backwards +2014-11-08: update documentation +2014-11-08: update changelog +2014-11-08: add support for reconstructing inflections index entries +2014-11-08: parsing of exth header failed in some cases +2014-11-08: fix: some links reconstruction in kf7 failed +2014-11-08: improve debug info +2014-11-08: failed malloc false reports +2014-11-03: fix problem with uncompressed documents +2014-11-03: fix broken locales +2014-11-03: remove obsolete includes +2014-11-03: git log > changelog +2014-11-03: improved buffer handling +2014-11-03: improved OPF for dictionaries +2014-11-03: proper rawml->orth initialization and freeing +2014-11-03: fix subject field in opf +2014-11-03: handle UTF-16 surrogates, make ORDT lookups locale independent +2014-11-01: move dict reconstruction to separate function +2014-11-01: cleanup +2014-11-01: quiet gcc warning on printf format +2014-11-01: reconstruction of orth dictionary entries +2014-09-27: use mobi_list_del_all() +2014-09-25: postpone conversion to utf8 after all source reconstructions +2014-09-24: comment +2014-09-24: comments +2014-09-12: doxygen comment +2014-09-12: data size in comment +2014-09-05: MOBIArray data type fix +2014-09-05: config.h fixes +2014-06-29: merge master +2014-04-11: initial commit \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/Makefile.am b/Charcoal/Charcoal/libmobi-public/Makefile.am new file mode 100644 index 0000000..7472fb5 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/Makefile.am @@ -0,0 +1,12 @@ +# project Makefile.am + +SUBDIRS = src tools tests + +EXTRA_DIST = README.md autogen.sh + +test: check + +ACLOCAL_AMFLAGS = -I m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libmobi.pc diff --git a/Charcoal/Charcoal/libmobi-public/NEWS b/Charcoal/Charcoal/libmobi-public/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/Charcoal/Charcoal/libmobi-public/README.md b/Charcoal/Charcoal/libmobi-public/README.md new file mode 100644 index 0000000..bfe1407 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/README.md @@ -0,0 +1,142 @@ +# Libmobi + +C library for handling Mobipocket/Kindle (MOBI) ebook format documents. + +Library comes with several [command line tools](https://github.com/bfabiszewski/libmobi/tree/public/tools) for working with mobi ebooks. +The tools source may also be used as an example on how to use the library. + +## Features: +- reading and parsing: + - some older text Palmdoc formats (pdb), + - Mobipocket files (prc, mobi), + - newer MOBI files including KF8 format (azw, azw3), + - Replica Print files (azw4) +- recreating source files using indices +- reconstructing references (links and embedded) in html files +- reconstructing source structure that can be fed back to kindlegen +- reconstructing dictionary markup (orth, infl tags) +- writing back loaded documents +- metadata editing +- handling encrypted documents +- encrypting documents for use on eInk Kindles + +## Todo: +- improve writing +- serialize rawml into raw records +- process RESC records + +## Doxygen documentation: +- [functions](http://www.fabiszewski.net/libmobi/group__mobi__export.html), +- [structures for the raw, unparsed records metadata and data](http://www.fabiszewski.net/libmobi/group__raw__structs.html), +- [structures for the parsed records metadata and data](http://www.fabiszewski.net/libmobi/group__parsed__structs.html), +- [enums](http://www.fabiszewski.net/libmobi/group__mobi__enums.html) + +## Source: +- [on github](https://github.com/bfabiszewski/libmobi/) + +## Packages: +[![Packaging status](https://repology.org/badge/vertical-allrepos/libmobi.svg)](https://repology.org/project/libmobi/versions) + +## Installation: + + [for git] $ ./autogen.sh + $ ./configure + $ make + [optionally] $ make test + $ sudo make install + +On macOS, you can install via [Homebrew](https://brew.sh/) with `brew install libmobi`. + +## Alternative build systems +- The supported way of building project is by using autotools. +- Optionally project provides basic support for CMake, Xcode and MSVC++ systems. However these alternative configurations are not covering all options of autotools project. They are also not tested and not updated regularly. + +## Usage +- single include file: `#include ` +- linker flag: `-lmobi` +- basic usage: +```c +#include + +/* Initialize main MOBIData structure */ +/* Must be deallocated with mobi_free() when not needed */ +MOBIData *m = mobi_init(); +if (m == NULL) { + return ERROR; +} + +/* Open file for reading */ +FILE *file = fopen(fullpath, "rb"); +if (file == NULL) { + mobi_free(m); + return ERROR; +} + +/* Load file into MOBIData structure */ +/* This structure will hold raw data/metadata from mobi document */ +MOBI_RET mobi_ret = mobi_load_file(m, file); +fclose(file); +if (mobi_ret != MOBI_SUCCESS) { + mobi_free(m); + return ERROR; +} + +/* Initialize MOBIRawml structure */ +/* Must be deallocated with mobi_free_rawml() when not needed */ +/* In the next step this structure will be filled with parsed data */ +MOBIRawml *rawml = mobi_init_rawml(m); +if (rawml == NULL) { + mobi_free(m); + return ERROR; +} +/* Raw data from MOBIData will be converted to html, css, fonts, media resources */ +/* Parsed data will be available in MOBIRawml structure */ +mobi_ret = mobi_parse_rawml(rawml, m); +if (mobi_ret != MOBI_SUCCESS) { + mobi_free(m); + mobi_free_rawml(rawml); + return ERROR; +} + +/* Do something useful here */ +/* ... */ +/* For examples how to access data in MOBIRawml structure see mobitool.c */ + +/* Free MOBIRawml structure */ +mobi_free_rawml(rawml); + +/* Free MOBIData structure */ +mobi_free(m); + +return SUCCESS; +``` +- for examples of usage, see [tools](https://github.com/bfabiszewski/libmobi/tree/public/tools) + + +## Requirements +- compiler supporting C99 +- zlib (optional, configure --with-zlib=no to use included miniz.c instead) +- libxml2 (optional, configure --with-libxml2=no to use internal xmlwriter) +- tested with gcc (>=4.2.4), clang (llvm >=3.4), sun c (>=5.13), MSVC++ (2015) +- builds on Linux, MacOS, Windows (MSVC++, MinGW), Android, Solaris +- tested architectures: x86, x86-64, arm, ppc +- works cross-compiled on Kindle :) + +## Tests +- [![Github Action status](https://github.com/bfabiszewski/libmobi/actions/workflows/build.yml/badge.svg)](https://github.com/bfabiszewski/libmobi/actions) +- [![Travis status](https://travis-ci.com/bfabiszewski/libmobi.svg?branch=public)](https://travis-ci.com/bfabiszewski/libmobi) +- [![Coverity status](https://scan.coverity.com/projects/3521/badge.svg)](https://scan.coverity.com/projects/3521) + +## Projects using libmobi +- [KyBook 2 Reader](http://kybook-reader.com) +- [@Voice Aloud Reader](http://www.hyperionics.com/atVoice/) +- [QLMobi quicklook plugin](https://github.com/bfabiszewski/QLMobi/tree/master/QLMobi) +- [Librera Reader](http://librera.mobi) +- ... (let me know to include your project) + +## License: +- LGPL, either version 3, or any later + +## Credits: +- The huffman decompression and KF8 parsing algorithms were learned by studying python source code of [KindleUnpack](https://github.com/kevinhendricks/KindleUnpack). +- Thanks to all contributors of Mobileread [MOBI wiki](http://wiki.mobileread.com/wiki/MOBI) diff --git a/Charcoal/Charcoal/libmobi-public/autogen.sh b/Charcoal/Charcoal/libmobi-public/autogen.sh new file mode 100644 index 0000000..13c49e3 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh +mkdir -p m4 && \ +autoreconf --force --install -I m4 diff --git a/Charcoal/Charcoal/libmobi-public/config.h b/Charcoal/Charcoal/libmobi-public/config.h new file mode 100644 index 0000000..f1d5a44 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/config.h @@ -0,0 +1 @@ +#define PACKAGE_VERSION "0.11" diff --git a/Charcoal/Charcoal/libmobi-public/configure.ac b/Charcoal/Charcoal/libmobi-public/configure.ac new file mode 100644 index 0000000..40629c4 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/configure.ac @@ -0,0 +1,419 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.62]) +AC_INIT([libmobi], [0.11]) +AC_CONFIG_SRCDIR([src/buffer.c]) + +# Enable automake +AM_INIT_AUTOMAKE([1.11 -Wall foreign subdir-objects]) +# all defined C macros (HAVE_*) will be saved to this file +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +# Checks for programs. +AC_PROG_CC +m4_version_prereq([2.70], [], [AC_PROG_CC_C99]) +AM_PROG_CC_C_O +AC_PROG_INSTALL +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + +# Init libtool +m4_ifdef([LT_INIT], [LT_INIT], [AC_PROG_LIBTOOL]) + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_STDBOOL +AC_CHECK_HEADERS([stdlib.h string.h utime.h unistd.h sys/resource.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_INT8_T +AC_TYPE_SIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MKTIME +AC_CHECK_FUNCS([memmove memset mkdir strdup strpbrk strrchr strstr strtoul utime]) + +# check for getopt() function +AC_MSG_CHECKING([for getopt]) +saved_CFLAGS="$CFLAGS" +CFLAGS="-Werror" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#if HAVE_UNISTD_H + # include + #endif]], + [[return getopt(0, NULL, NULL);]])], + [have_getopt=yes + AC_DEFINE([HAVE_GETOPT], [1], [Define whether getopt() function is available])], + [have_getopt=no]) +CFLAGS="$saved_CFLAGS" +AC_MSG_RESULT([$have_getopt]) +AM_CONDITIONAL([USE_INTERNAL_GETOPT], [test x$have_getopt = xno]) + +# Check for oracle solaris studio c compiler +AC_CHECK_DECL([__SUNPRO_C], [SUNCC=yes], [SUNCC=no]) + +# Get rid of extended attributes in release archive on macOS +case "$host" in + *-*-darwin*) + am__tar="COPY_EXTENDED_ATTRIBUTES_DISABLE=1 COPYFILE_DISABLE=1 ${am__tar}" +esac + +# Check for -fvisibility=hidden to determine if we can do GNU-style +# visibility attributes for symbol export control +AC_MSG_CHECKING([for visibility hidden compiler flag]) +VISIBILITY_HIDDEN= +if test x$SUNCC = xyes; then + # check if we can use -xldscope=hidden + saved_CFLAGS="$CFLAGS" + CFLAGS="-xldscope=hidden" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]], [[]])], + [enable_fvisibility_hidden=yes], + [enable_fvisibility_hidden=no]) + CFLAGS="$saved_CFLAGS" + + AS_IF([test x$enable_fvisibility_hidden = xyes], [VISIBILITY_HIDDEN="-xldscope=hidden"]) +else + case "$host" in + *-*-mingw*) + # on mingw32 we do -fvisibility=hidden and __declspec(dllexport) + VISIBILITY_HIDDEN="-fvisibility=hidden" + ;; + *) + # on other compilers, check if we can do -fvisibility=hidden + saved_CFLAGS="$CFLAGS" + CFLAGS="-fvisibility=hidden -Werror" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]], [[]])], + [enable_fvisibility_hidden=yes], + [enable_fvisibility_hidden=no]) + CFLAGS="$saved_CFLAGS" + + AS_IF([test x$enable_fvisibility_hidden = xyes], [VISIBILITY_HIDDEN="-fvisibility=hidden"]) + ;; + esac +fi +AC_MSG_RESULT([$VISIBILITY_HIDDEN]) +AC_SUBST([VISIBILITY_HIDDEN]) + +# MinGW seems to need this +case "$host" in + *-*-mingw*) + NO_UNDEFINED="-no-undefined" + AVOID_VERSION="-avoid-version" + ISO99_SOURCE="-D_ISOC99_SOURCE=1" + WIN32=yes + ;; + *) + NO_UNDEFINED= + AVOID_VERSION= + ISO99_SOURCE= + WIN32=no + ;; +esac +AC_SUBST([NO_UNDEFINED]) +AC_SUBST([AVOID_VERSION]) +AC_SUBST([ISO99_SOURCE]) +AC_SUBST([WIN32]) + +# Override default versioning of Darwin linker +case "$host" in + *-*-darwin*) + case "$host" in + # exclude ppc as it breaks linker + ppc-* | powerpc-*) + DARWIN_LDFLAGS= + ;; + *) + MAJOR=`echo "${PACKAGE_VERSION}" | cut -d . -f 1` + DARWIN_LDFLAGS="-Wl,-compatibility_version,${MAJOR} -Wl,-current_version,${PACKAGE_VERSION}" + ;; + esac + ;; + *) + DARWIN_LDFLAGS= + ;; +esac +AC_SUBST([DARWIN_LDFLAGS]) + +# Check for --allow-multiple-definition support in linker +AC_MSG_CHECKING([whether linker supports --allow-multiple-definition flag]) +MOBI_ALLOW_MULTIPLE= +saved_CFLAGS="$CFLAGS" +CFLAGS="-Wl,--allow-multiple-definition -Werror" +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]], [[]])], + [def_allow_multiple=yes], + [def_allow_multiple=no]) +CFLAGS="$saved_CFLAGS" +AS_IF([test x$def_allow_multiple = xyes], [MOBI_ALLOW_MULTIPLE="-Wl,--allow-multiple-definition"]) +AC_MSG_RESULT([$def_allow_multiple]) +AC_SUBST([MOBI_ALLOW_MULTIPLE]) + +# Check for non-broken inline under various spellings +AC_MSG_CHECKING([for inline keyword]) +def_inline="" +for inline_key in inline __inline__ __inline +do + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[]], + [[} $inline_key int foo() { return 0; } int bar() { return foo();]])], + [def_inline=$inline_key; break]) +done +AC_MSG_RESULT([$def_inline]) +AC_DEFINE_UNQUOTED([MOBI_INLINE], [$def_inline], [How to obtain function inlining.]) + +# Check for noreturn attribute support +AC_MSG_CHECKING([whether compiler supports noreturn attribute]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[]], [[void foo( void ) __attribute__((noreturn));]])], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_ATTRIBUTE_NORETURN], [1], [Define to 1 if compiler supports __attribute__((noreturn))])], + [AC_MSG_RESULT([no])] +) + +# Check --enable-xmlwriter +XMLWRITER_OPT="" +AC_MSG_CHECKING([whether enable xmlwriter (for opf support)]) +AC_ARG_ENABLE( + [xmlwriter], + [AS_HELP_STRING([--enable-xmlwriter], [enable xmlwriter (for opf support) @<:@default=yes@:>@])], + [case "$enableval" in + yes) xmlwriter=yes ;; + no) xmlwriter=no ;; + *) AC_MSG_ERROR([bad value $enableval for --enable-xmlwriter]) ;; + esac], + [xmlwriter=yes]) +AC_MSG_RESULT([$xmlwriter]) +AM_CONDITIONAL([USE_XMLWRITER], [test x$xmlwriter = xyes]) +if test x$xmlwriter = xyes; then + AC_DEFINE([USE_XMLWRITER], [1], [Define whether enable xmlwriter (for opf support)]) + + # test for --with-libxml2 + AC_MSG_CHECKING([whether compile with libxml2]) + AC_ARG_WITH( + [libxml2], + [AS_HELP_STRING([--with-libxml2], [Use libxml2 instead of internal xmlwriter @<:@default=yes@:>@])], + [if test "x$withval" = xyes; then use_libxml2=yes; else use_libxml2=no; fi], + [use_libxml2=yes]) + AC_MSG_RESULT([$use_libxml2]) + + if test x$use_libxml2 = xyes; then + AC_ARG_VAR([XML2_CONFIG], [path to xml2-config utility]) + AC_CHECK_PROGS([XML2_CONFIG], [xml2-config]) + AC_CHECK_PROGS([PKG_CONFIG], [pkg-config]) + AC_MSG_CHECKING([for libxml2 path supplier]) + if test -n "$PKG_CONFIG" && $PKG_CONFIG --exists libxml-2.0; then + LIBXML2_CFLAGS="`$PKG_CONFIG --cflags libxml-2.0`" + LIBXML2_LDFLAGS="`$PKG_CONFIG --libs libxml-2.0`" + AC_MSG_RESULT([pkg-config]) + elif test -n "$XML2_CONFIG"; then + LIBXML2_CFLAGS="`$XML2_CONFIG --cflags`" + LIBXML2_LDFLAGS="`$XML2_CONFIG --libs`" + AC_MSG_RESULT([xml2-config]) + else + LIBXML2_CFLAGS=-I/usr/include/libxml2 + LIBXML2_LDFLAGS=-lxml2 + AC_MSG_RESULT([generic]) + fi + saved_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBXML2_CFLAGS" + AC_CHECK_HEADER( + [libxml/xmlwriter.h], + [AC_DEFINE([USE_LIBXML2], [1], [Define if you want to use libxml2 library])], + [AC_MSG_ERROR([couldn't find libxml2])]) + CPPFLAGS=$saved_CPPFLAGS + else + LIBXML2_LDFLAGS= + LIBXML2_CFLAGS= + fi + AC_SUBST([LIBXML2_LDFLAGS]) + AC_SUBST([LIBXML2_CFLAGS]) + XMLWRITER_OPT="yes" +fi +AM_CONDITIONAL([USE_LIBXML2], [test x$use_libxml2 = xyes]) +AC_SUBST([XMLWRITER_OPT]) + +# Check --enable-encryption +ENCRYPTION_OPT="" +AC_MSG_CHECKING([whether enable encryption]) +AC_ARG_ENABLE( + [encryption], + [AS_HELP_STRING([--enable-encryption], [enable encryption @<:@default=yes@:>@])], + [case "$enableval" in + yes) encryption=yes ;; + no) encryption=no ;; + *) AC_MSG_ERROR([bad value $enableval for --enable-encryption]) ;; + esac], + [encryption=yes]) +AC_MSG_RESULT([$encryption]) +AM_CONDITIONAL([USE_ENCRYPTION], [test x$encryption = xyes]) +if test x$encryption = xyes; then + AC_DEFINE([USE_ENCRYPTION], [1], [Enable encryption]) + ENCRYPTION_OPT="yes" + + AC_CHECK_HEADERS([sys/random.h]) + AC_MSG_CHECKING([for getrandom with a standard API]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #ifdef HAVE_UNISTD_H + # include + #endif + #ifdef HAVE_SYS_RANDOM_H + # include + #endif]], + [[unsigned char buf; + if (&getrandom != NULL) { + (void) getrandom((void *) &buf, 1U, 0U); + }]])], + [AC_MSG_RESULT([yes]) + AC_CHECK_FUNCS([getrandom])], + [AC_MSG_RESULT([no])]) + +fi +AC_SUBST([ENCRYPTION_OPT]) + +# Check --enable-debug +AC_MSG_CHECKING([whether enable debugging]) +AC_ARG_ENABLE( + [debug], + [AS_HELP_STRING([--enable-debug], [enable debugging @<:@default=no@:>@])], + [case "$enableval" in + yes) debug=yes ;; + no) debug=no ;; + *) AC_MSG_ERROR([bad value $enableval for --enable-debug]) ;; + esac], + [debug=no]) +AC_MSG_RESULT([$debug]) + +DEBUG_CFLAGS= +if test x$debug = xyes; then + AC_DEFINE([MOBI_DEBUG], [1], [Enable debugging]) + if test x$SUNCC = xyes; then + DEBUG_CFLAGS="-v -errwarn" + else + DEBUG_CFLAGS="-pedantic -Wall -Wextra -Werror" + fi +fi +AC_SUBST([DEBUG_CFLAGS]) + +# Check --enable-debug-alloc +AC_MSG_CHECKING([whether enable alloc debugging]) +AC_ARG_ENABLE( + [debug_alloc], + [AS_HELP_STRING([--enable-debug-alloc], [enable memory allocation debugging @<:@default=no@:>@])], + [case "$enableval" in + yes) debug_alloc=yes ;; + no) debug_alloc=no ;; + *) AC_MSG_ERROR([bad value $enableval for --enable-debug-alloc]) ;; + esac], + [debug_alloc=no]) +AC_MSG_RESULT([$debug_alloc]) + +if test x$debug_alloc = xyes; then + AC_DEFINE([MOBI_DEBUG_ALLOC], [1], [Enable alloc debugging]) +fi + +# Check --enable-tools-static +AC_MSG_CHECKING([whether link tools against static libmobi]) +AC_ARG_ENABLE( + [tools_static], + [AS_HELP_STRING([--enable-tools-static], [link tools against static libmobi @<:@default=no@:>@])], + [case "$enableval" in + yes) tools_static=yes ;; + no) tools_static=no ;; + *) AC_MSG_ERROR([bad value $enableval for --enable-tools-static]) ;; + esac], + [tools_static=no]) +AC_MSG_RESULT([$tools_static]) +TOOLS_STATIC= +if test x$tools_static = xyes; then + TOOLS_STATIC="-static" +fi +AC_SUBST([TOOLS_STATIC]) + +# test for --with-zlib +AC_MSG_CHECKING([whether compile with zlib]) +AC_ARG_WITH( + [zlib], + [AS_HELP_STRING([--with-zlib], [Use zlib instead of included miniz @<:@default=yes@:>@])], + [if test "x$withval" = xyes; then use_zlib=yes; else use_zlib=no; fi], + [use_zlib=yes]) +AC_MSG_RESULT([$use_zlib]) +AM_CONDITIONAL([USE_ZLIB], [test x$use_zlib = xyes]) +AM_CONDITIONAL([USE_MINIZ], [test x$use_zlib = xno]) +AM_CONDITIONAL([USE_STATIC], [test x$tools_static = xyes]) +if test x$use_zlib = xyes; then + AC_CHECK_HEADER( + [zlib.h], + [AC_DEFINE([USE_ZLIB], [1], [Define if you want to use system zlib library]) + LIBZ_LDFLAGS=-lz + MINIZ_CFLAGS=], + [AC_MSG_ERROR([couldn't find zlib header])]) +else + AC_DEFINE([USE_MINIZ], [1], [Define if you want to use included miniz library]) + MINIZ_CFLAGS="-D_POSIX_C_SOURCE=200112L" + LIBZ_LDFLAGS= +fi +AC_SUBST([LIBZ_LDFLAGS]) +AC_SUBST([MINIZ_CFLAGS]) + +# Check for md5 or md5sum program, needed for tests +AC_ARG_VAR([MD5PROG], [md5 hashing program executable]) +AS_IF([test -z "$MD5PROG"], [AC_CHECK_PROG([MD5PROG], [md5sum], [md5sum -t])], []) +AS_IF([test -z "$MD5PROG"], [AC_CHECK_PROG([MD5PROG], [md5], [md5 -r])], []) +AS_IF([test -z "$MD5PROG"], [AC_MSG_WARN([md5 hashing program not found, some tests will be skipped])], []) +AC_PATH_PROG([BASH_PATH], [bash]) +AS_IF( + [test -z "$BASH_PATH"], + [AC_MSG_WARN([bash not found, tests will be skipped]) + RUN_TESTS="no"], + [RUN_TESTS="yes" + AC_SUBST([BASH_PATH])]) +AC_SUBST([RUN_TESTS]) + +if test x$RUN_TESTS = xyes; then + # List test files + cur_dir=`pwd` + cd "$srcdir"/tests + + for sample_path in samples/*.mobi + do + TESTLIST="${TESTLIST} ${sample_path} \\ +" + done + for sample_path in samples/*.fail + do + TESTLIST="${TESTLIST} ${sample_path} \\ +" + FAILLIST="${FAILLIST} ${sample_path} \\ +" + done + cd $cur_dir +fi + +AC_SUBST([TESTLIST]) +AC_SUBST([FAILLIST]) + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([libmobi.pc]) +AC_CONFIG_FILES([src/Makefile]) +AC_CONFIG_FILES([tools/Makefile]) +AC_CONFIG_FILES([tools/mobitool.1]) +AC_CONFIG_FILES([tools/mobimeta.1]) +AC_CONFIG_FILES([tools/mobidrm.1]) +AC_CONFIG_FILES([tests/Makefile]) +AC_CONFIG_FILES([tests/test.sh], [chmod +x tests/test.sh]) + +AC_OUTPUT diff --git a/Charcoal/Charcoal/libmobi-public/libmobi.pc.in b/Charcoal/Charcoal/libmobi-public/libmobi.pc.in new file mode 100644 index 0000000..ccfb623 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/libmobi.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libmobi +Description: MOBI ebook format handling library +URL: http://www.fabiszewski.net/libmobi +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lmobi +Libs.private: @LIBZ_LDFLAGS@ @LIBXML2_LDFLAGS@ +Cflags: -I${includedir} diff --git a/Charcoal/Charcoal/libmobi-public/mobi.xcodeproj/project.pbxproj b/Charcoal/Charcoal/libmobi-public/mobi.xcodeproj/project.pbxproj new file mode 100644 index 0000000..04cb3d3 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/mobi.xcodeproj/project.pbxproj @@ -0,0 +1,879 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1502448F1CD3A18F0075F4EC /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 1502448D1CD3A18F0075F4EC /* sha1.c */; }; + 150244901CD3A18F0075F4EC /* sha1.h in Headers */ = {isa = PBXBuildFile; fileRef = 1502448E1CD3A18F0075F4EC /* sha1.h */; }; + 1504FD851CBE880B002AA042 /* meta.c in Sources */ = {isa = PBXBuildFile; fileRef = 1504FD831CBE880B002AA042 /* meta.c */; }; + 1504FD861CBE880B002AA042 /* meta.h in Headers */ = {isa = PBXBuildFile; fileRef = 1504FD841CBE880B002AA042 /* meta.h */; }; + 150A318D18E19BF9001A7AD7 /* write.c in Sources */ = {isa = PBXBuildFile; fileRef = 150A318C18E19BF9001A7AD7 /* write.c */; }; + 151A46661909312900FAF3F4 /* miniz.c in Sources */ = {isa = PBXBuildFile; fileRef = 151A46651909312900FAF3F4 /* miniz.c */; settings = {COMPILER_FLAGS = "-w"; }; }; + 152FD1E6270509A900AF276A /* randombytes.h in Headers */ = {isa = PBXBuildFile; fileRef = 152FD1E4270509A900AF276A /* randombytes.h */; }; + 152FD1E7270509A900AF276A /* randombytes.c in Sources */ = {isa = PBXBuildFile; fileRef = 152FD1E5270509A900AF276A /* randombytes.c */; }; + 153D91DB18E9630000E807B6 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 153D91DA18E9630000E807B6 /* memory.c */; }; + 1543065B1CB78A45006AB398 /* mobimeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 151185A31CB6C28500201C8A /* mobimeta.c */; }; + 1543065E1CB78BA8006AB398 /* libmobi.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 150039BB18E06BC100D33077 /* libmobi.dylib */; }; + 154C2D401CC64A170041DD0E /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 154C2D3E1CC64A170041DD0E /* common.c */; }; + 154C2D411CC64A170041DD0E /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 154C2D3E1CC64A170041DD0E /* common.c */; }; + 1550ADC318E427D7006F9257 /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 1550ADC218E427D7006F9257 /* buffer.c */; }; + 1550ADCE18E4B925006F9257 /* compression.c in Sources */ = {isa = PBXBuildFile; fileRef = 1550ADCD18E4B925006F9257 /* compression.c */; }; + 1553330118E359AE00334E23 /* read.c in Sources */ = {isa = PBXBuildFile; fileRef = 1553330018E359AE00334E23 /* read.c */; }; + 1553332118E37FC400334E23 /* libmobi.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 150039BB18E06BC100D33077 /* libmobi.dylib */; }; + 15603889192D2E1A002EDB1A /* opf.c in Sources */ = {isa = PBXBuildFile; fileRef = 15603888192D2E1A002EDB1A /* opf.c */; }; + 15615F0818F58C85004EBB6E /* mobitool.c in Sources */ = {isa = PBXBuildFile; fileRef = 15615F0718F58C85004EBB6E /* mobitool.c */; }; + 1563314718EC36A200D4B858 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 1563314618EC36A200D4B858 /* debug.c */; }; + 156AA65D1C81A3860085335A /* xmlwriter.c in Sources */ = {isa = PBXBuildFile; fileRef = 156AA65B1C81A3860085335A /* xmlwriter.c */; }; + 156AA65E1C81A3860085335A /* xmlwriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 156AA65C1C81A3860085335A /* xmlwriter.h */; }; + 157BEA732747BEDA004984B8 /* libmobi.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 150039BB18E06BC100D33077 /* libmobi.dylib */; }; + 157BEA852747BF13004984B8 /* mobidrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 157BEA6B2747B4EC004984B8 /* mobidrm.c */; }; + 157BEA8A2747BF26004984B8 /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 154C2D3E1CC64A170041DD0E /* common.c */; }; + 157DF7AD191A514D00191502 /* index.c in Sources */ = {isa = PBXBuildFile; fileRef = 157DF7AC191A514D00191502 /* index.c */; }; + 15AB2CB419572C2800EB7F74 /* parse_rawml.c in Sources */ = {isa = PBXBuildFile; fileRef = 15AB2CB319572C2800EB7F74 /* parse_rawml.c */; }; + 15EA81DF1A14D5AC00138554 /* structure.c in Sources */ = {isa = PBXBuildFile; fileRef = 15EA81DE1A14D5AC00138554 /* structure.c */; }; + 15F1A1D118F4192D009CFE05 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 15F1A1D018F4192D009CFE05 /* util.c */; }; + 15FB2BB21A1A32970052D5C5 /* encryption.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FB2BB01A1A32970052D5C5 /* encryption.c */; }; + 15FB2BB31A1A32970052D5C5 /* encryption.h in Headers */ = {isa = PBXBuildFile; fileRef = 15FB2BB11A1A32970052D5C5 /* encryption.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1543065C1CB78B78006AB398 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 150039B318E06BC100D33077 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 150039BA18E06BC100D33077; + remoteInfo = mobi; + }; + 1553331F18E37FB800334E23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 150039B318E06BC100D33077 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 150039BA18E06BC100D33077; + remoteInfo = mobi; + }; + 157BEA6E2747BEDA004984B8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 150039B318E06BC100D33077 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 150039BA18E06BC100D33077; + remoteInfo = mobi; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 154306521CB78A3D006AB398 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 1553331418E37F7000334E23 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 157BEA742747BEDA004984B8 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 150039BB18E06BC100D33077 /* libmobi.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmobi.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 150039C218E06C1B00D33077 /* mobi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = mobi.h; path = src/mobi.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 1502448D1CD3A18F0075F4EC /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sha1.c; path = src/sha1.c; sourceTree = ""; }; + 1502448E1CD3A18F0075F4EC /* sha1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sha1.h; path = src/sha1.h; sourceTree = ""; }; + 1504FD831CBE880B002AA042 /* meta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = meta.c; path = src/meta.c; sourceTree = ""; }; + 1504FD841CBE880B002AA042 /* meta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = meta.h; path = src/meta.h; sourceTree = ""; }; + 150A318B18E19BD8001A7AD7 /* write.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = write.h; path = src/write.h; sourceTree = ""; }; + 150A318C18E19BF9001A7AD7 /* write.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = write.c; path = src/write.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 151185A31CB6C28500201C8A /* mobimeta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mobimeta.c; path = tools/mobimeta.c; sourceTree = SOURCE_ROOT; }; + 151A46641909302C00FAF3F4 /* miniz.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = miniz.h; path = src/miniz.h; sourceTree = ""; }; + 151A46651909312900FAF3F4 /* miniz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = miniz.c; path = src/miniz.c; sourceTree = ""; }; + 152D509E1BD79AE400E91C09 /* test.sh.in */ = {isa = PBXFileReference; explicitFileType = text.script.sh; name = test.sh.in; path = tests/test.sh.in; sourceTree = ""; }; + 152D50A01BD7A08300E91C09 /* Makefile.am */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.am; path = tests/Makefile.am; sourceTree = ""; usesTabs = 1; xcLanguageSpecificationIdentifier = xcode.lang.sh; }; + 152E5D1218F5DEB100B05EC9 /* configure.ac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = configure.ac; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.csh; }; + 152E5D1318F5DEB100B05EC9 /* Makefile.am */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile.am; sourceTree = ""; usesTabs = 1; }; + 152E5D1418F5DEC000B05EC9 /* Makefile.am */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.am; path = src/Makefile.am; sourceTree = ""; usesTabs = 1; }; + 152E5D1518F5DECF00B05EC9 /* Makefile.am */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; name = Makefile.am; path = tools/Makefile.am; sourceTree = ""; usesTabs = 1; }; + 152E5D1618F5E22000B05EC9 /* autogen.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = autogen.sh; sourceTree = ""; }; + 152ED797195EFBD900ACD1AD /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + 152FD1E4270509A900AF276A /* randombytes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = randombytes.h; path = src/randombytes.h; sourceTree = ""; }; + 152FD1E5270509A900AF276A /* randombytes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = randombytes.c; path = src/randombytes.c; sourceTree = ""; }; + 153967601907C0AA00EDC923 /* COPYING */ = {isa = PBXFileReference; lastKnownFileType = text; path = COPYING; sourceTree = ""; }; + 153D91DA18E9630000E807B6 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = memory.c; path = src/memory.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 153D91DC18E9633500E807B6 /* memory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = memory.h; path = src/memory.h; sourceTree = ""; }; + 1542B8041C7FA5E800C5122F /* getopt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = getopt.c; path = tools/win32/getopt.c; sourceTree = SOURCE_ROOT; }; + 1542B8051C7FA5E900C5122F /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = getopt.h; path = tools/win32/getopt.h; sourceTree = SOURCE_ROOT; }; + 154306541CB78A3D006AB398 /* mobimeta */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mobimeta; sourceTree = BUILT_PRODUCTS_DIR; }; + 154C2D3E1CC64A170041DD0E /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common.c; path = tools/common.c; sourceTree = SOURCE_ROOT; }; + 154C2D3F1CC64A170041DD0E /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = common.h; path = tools/common.h; sourceTree = SOURCE_ROOT; }; + 1550ADC218E427D7006F9257 /* buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = buffer.c; path = src/buffer.c; sourceTree = ""; }; + 1550ADC418E42842006F9257 /* buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = buffer.h; path = src/buffer.h; sourceTree = ""; }; + 1550ADCD18E4B925006F9257 /* compression.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = compression.c; path = src/compression.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 1550ADCF18E4BB83006F9257 /* compression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = compression.h; path = src/compression.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 1553330018E359AE00334E23 /* read.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = read.c; path = src/read.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 1553330218E359B900334E23 /* read.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = read.h; path = src/read.h; sourceTree = ""; }; + 1553331618E37F7000334E23 /* mobitool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mobitool; sourceTree = BUILT_PRODUCTS_DIR; }; + 1559D790191BB06700636661 /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = config.h; path = src/config.h; sourceTree = ""; }; + 15603888192D2E1A002EDB1A /* opf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = opf.c; path = src/opf.c; sourceTree = ""; }; + 1560388A192D2E34002EDB1A /* opf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = opf.h; path = src/opf.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 15615F0718F58C85004EBB6E /* mobitool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = mobitool.c; path = tools/mobitool.c; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 1563314518EC367300D4B858 /* debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = debug.h; path = src/debug.h; sourceTree = ""; }; + 1563314618EC36A200D4B858 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug.c; path = src/debug.c; sourceTree = ""; }; + 156AA65B1C81A3860085335A /* xmlwriter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xmlwriter.c; path = src/xmlwriter.c; sourceTree = ""; }; + 156AA65C1C81A3860085335A /* xmlwriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xmlwriter.h; path = src/xmlwriter.h; sourceTree = ""; }; + 157BEA6B2747B4EC004984B8 /* mobidrm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mobidrm.c; path = tools/mobidrm.c; sourceTree = SOURCE_ROOT; }; + 157BEA782747BEDA004984B8 /* mobidrm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mobidrm; sourceTree = BUILT_PRODUCTS_DIR; }; + 157DF7AC191A514D00191502 /* index.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = index.c; path = src/index.c; sourceTree = ""; }; + 157DF7AE191A51A400191502 /* index.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = index.h; path = src/index.h; sourceTree = ""; }; + 15843DFE19215D0400587C89 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = ""; }; + 158F44DC191E88010000F44A /* libmobi.pc.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = libmobi.pc.in; sourceTree = ""; }; + 15AB2CB319572C2800EB7F74 /* parse_rawml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parse_rawml.c; path = src/parse_rawml.c; sourceTree = ""; }; + 15AB2CB519572C4400EB7F74 /* parse_rawml.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = parse_rawml.h; path = src/parse_rawml.h; sourceTree = ""; }; + 15B4311D2767840300B7E6A7 /* mobidrm.1.in */ = {isa = PBXFileReference; explicitFileType = text.man; name = mobidrm.1.in; path = tools/mobidrm.1.in; sourceTree = SOURCE_ROOT; }; + 15D7CFD71A167A3A00F08927 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = tools/README.md; sourceTree = ""; }; + 15E5FAD91CC58B4D00F700D1 /* mobimeta.1.in */ = {isa = PBXFileReference; explicitFileType = text.man; name = mobimeta.1.in; path = tools/mobimeta.1.in; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.man; }; + 15E65B5E1A1DF1DA00B7FBBD /* mobitool.1.in */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 4; name = mobitool.1.in; path = tools/mobitool.1.in; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.man; }; + 15E65B5F1A1E0FC100B7FBBD /* .travis.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.simpleColoring; }; + 15EA81DD1A14D58500138554 /* structure.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = structure.h; path = src/structure.h; sourceTree = SOURCE_ROOT; }; + 15EA81DE1A14D5AC00138554 /* structure.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = structure.c; path = src/structure.c; sourceTree = ""; }; + 15F1A1D018F4192D009CFE05 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = util.c; path = src/util.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + 15F1A1D218F4195A009CFE05 /* util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = util.h; path = src/util.h; sourceTree = ""; }; + 15FB2BB01A1A32970052D5C5 /* encryption.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = encryption.c; path = src/encryption.c; sourceTree = ""; }; + 15FB2BB11A1A32970052D5C5 /* encryption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = encryption.h; path = src/encryption.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 150039B818E06BC100D33077 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 154306511CB78A3D006AB398 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1543065E1CB78BA8006AB398 /* libmobi.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1553331318E37F7000334E23 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1553332118E37FC400334E23 /* libmobi.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 157BEA722747BEDA004984B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 157BEA732747BEDA004984B8 /* libmobi.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 150039B218E06BC100D33077 = { + isa = PBXGroup; + children = ( + 152D509F1BD79AED00E91C09 /* tests */, + 1539675F1907BC0600EDC923 /* docs */, + 1550ADC218E427D7006F9257 /* buffer.c */, + 1550ADC418E42842006F9257 /* buffer.h */, + 1550ADCD18E4B925006F9257 /* compression.c */, + 1550ADCF18E4BB83006F9257 /* compression.h */, + 1559D790191BB06700636661 /* config.h */, + 1563314618EC36A200D4B858 /* debug.c */, + 1563314518EC367300D4B858 /* debug.h */, + 15FB2BB01A1A32970052D5C5 /* encryption.c */, + 15FB2BB11A1A32970052D5C5 /* encryption.h */, + 157DF7AC191A514D00191502 /* index.c */, + 157DF7AE191A51A400191502 /* index.h */, + 153D91DA18E9630000E807B6 /* memory.c */, + 153D91DC18E9633500E807B6 /* memory.h */, + 1504FD831CBE880B002AA042 /* meta.c */, + 1504FD841CBE880B002AA042 /* meta.h */, + 151A46651909312900FAF3F4 /* miniz.c */, + 151A46641909302C00FAF3F4 /* miniz.h */, + 150039C218E06C1B00D33077 /* mobi.h */, + 15603888192D2E1A002EDB1A /* opf.c */, + 1560388A192D2E34002EDB1A /* opf.h */, + 15AB2CB319572C2800EB7F74 /* parse_rawml.c */, + 15AB2CB519572C4400EB7F74 /* parse_rawml.h */, + 152FD1E4270509A900AF276A /* randombytes.h */, + 152FD1E5270509A900AF276A /* randombytes.c */, + 1553330018E359AE00334E23 /* read.c */, + 1553330218E359B900334E23 /* read.h */, + 1502448D1CD3A18F0075F4EC /* sha1.c */, + 1502448E1CD3A18F0075F4EC /* sha1.h */, + 15EA81DE1A14D5AC00138554 /* structure.c */, + 15EA81DD1A14D58500138554 /* structure.h */, + 15F1A1D018F4192D009CFE05 /* util.c */, + 15F1A1D218F4195A009CFE05 /* util.h */, + 150A318C18E19BF9001A7AD7 /* write.c */, + 150A318B18E19BD8001A7AD7 /* write.h */, + 156AA65B1C81A3860085335A /* xmlwriter.c */, + 156AA65C1C81A3860085335A /* xmlwriter.h */, + 1553331718E37F7100334E23 /* tools */, + 150039BC18E06BC100D33077 /* Products */, + 152E5CFE18F5DB3200B05EC9 /* autotools */, + ); + sourceTree = ""; + }; + 150039BC18E06BC100D33077 /* Products */ = { + isa = PBXGroup; + children = ( + 150039BB18E06BC100D33077 /* libmobi.dylib */, + 1553331618E37F7000334E23 /* mobitool */, + 154306541CB78A3D006AB398 /* mobimeta */, + 157BEA782747BEDA004984B8 /* mobidrm */, + ); + name = Products; + sourceTree = ""; + }; + 152D509F1BD79AED00E91C09 /* tests */ = { + isa = PBXGroup; + children = ( + 152D509E1BD79AE400E91C09 /* test.sh.in */, + 152D50A01BD7A08300E91C09 /* Makefile.am */, + ); + name = tests; + sourceTree = ""; + }; + 152E5CFE18F5DB3200B05EC9 /* autotools */ = { + isa = PBXGroup; + children = ( + 152E5D1618F5E22000B05EC9 /* autogen.sh */, + 152E5D1218F5DEB100B05EC9 /* configure.ac */, + 158F44DC191E88010000F44A /* libmobi.pc.in */, + 152E5D1518F5DECF00B05EC9 /* Makefile.am */, + 152E5D1418F5DEC000B05EC9 /* Makefile.am */, + 152E5D1318F5DEB100B05EC9 /* Makefile.am */, + ); + name = autotools; + sourceTree = ""; + }; + 1539675F1907BC0600EDC923 /* docs */ = { + isa = PBXGroup; + children = ( + 152ED797195EFBD900ACD1AD /* ChangeLog */, + 15843DFE19215D0400587C89 /* README.md */, + 15D7CFD71A167A3A00F08927 /* README.md */, + 15E65B5F1A1E0FC100B7FBBD /* .travis.yml */, + 153967601907C0AA00EDC923 /* COPYING */, + 15B4311D2767840300B7E6A7 /* mobidrm.1.in */, + 15E65B5E1A1DF1DA00B7FBBD /* mobitool.1.in */, + 15E5FAD91CC58B4D00F700D1 /* mobimeta.1.in */, + ); + name = docs; + sourceTree = ""; + }; + 1553331718E37F7100334E23 /* tools */ = { + isa = PBXGroup; + children = ( + 151185A31CB6C28500201C8A /* mobimeta.c */, + 15615F0718F58C85004EBB6E /* mobitool.c */, + 1542B8041C7FA5E800C5122F /* getopt.c */, + 1542B8051C7FA5E900C5122F /* getopt.h */, + 154C2D3E1CC64A170041DD0E /* common.c */, + 154C2D3F1CC64A170041DD0E /* common.h */, + 157BEA6B2747B4EC004984B8 /* mobidrm.c */, + ); + name = tools; + path = test; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 150039B918E06BC100D33077 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 15FB2BB31A1A32970052D5C5 /* encryption.h in Headers */, + 152FD1E6270509A900AF276A /* randombytes.h in Headers */, + 150244901CD3A18F0075F4EC /* sha1.h in Headers */, + 156AA65E1C81A3860085335A /* xmlwriter.h in Headers */, + 1504FD861CBE880B002AA042 /* meta.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 150039BA18E06BC100D33077 /* mobi */ = { + isa = PBXNativeTarget; + buildConfigurationList = 150039BF18E06BC100D33077 /* Build configuration list for PBXNativeTarget "mobi" */; + buildPhases = ( + 150039B718E06BC100D33077 /* Sources */, + 150039B818E06BC100D33077 /* Frameworks */, + 150039B918E06BC100D33077 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = mobi; + productName = libmobi; + productReference = 150039BB18E06BC100D33077 /* libmobi.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; + 154306531CB78A3D006AB398 /* mobimeta */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1543065A1CB78A3D006AB398 /* Build configuration list for PBXNativeTarget "mobimeta" */; + buildPhases = ( + 154306501CB78A3D006AB398 /* Sources */, + 154306511CB78A3D006AB398 /* Frameworks */, + 154306521CB78A3D006AB398 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 1543065D1CB78B78006AB398 /* PBXTargetDependency */, + ); + name = mobimeta; + productName = write_test; + productReference = 154306541CB78A3D006AB398 /* mobimeta */; + productType = "com.apple.product-type.tool"; + }; + 1553331518E37F7000334E23 /* mobitool */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1553331C18E37F7100334E23 /* Build configuration list for PBXNativeTarget "mobitool" */; + buildPhases = ( + 1553331218E37F7000334E23 /* Sources */, + 1553331318E37F7000334E23 /* Frameworks */, + 1553331418E37F7000334E23 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 1553332018E37FB800334E23 /* PBXTargetDependency */, + ); + name = mobitool; + productName = test; + productReference = 1553331618E37F7000334E23 /* mobitool */; + productType = "com.apple.product-type.tool"; + }; + 157BEA6C2747BEDA004984B8 /* mobidrm */ = { + isa = PBXNativeTarget; + buildConfigurationList = 157BEA752747BEDA004984B8 /* Build configuration list for PBXNativeTarget "mobidrm" */; + buildPhases = ( + 157BEA6F2747BEDA004984B8 /* Sources */, + 157BEA722747BEDA004984B8 /* Frameworks */, + 157BEA742747BEDA004984B8 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 157BEA6D2747BEDA004984B8 /* PBXTargetDependency */, + ); + name = mobidrm; + productName = test; + productReference = 157BEA782747BEDA004984B8 /* mobidrm */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 150039B318E06BC100D33077 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1420; + ORGANIZATIONNAME = "Bartek Fabiszewski"; + TargetAttributes = { + 154306531CB78A3D006AB398 = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = 150039B618E06BC100D33077 /* Build configuration list for PBXProject "mobi" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 150039B218E06BC100D33077; + productRefGroup = 150039BC18E06BC100D33077 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 150039BA18E06BC100D33077 /* mobi */, + 1553331518E37F7000334E23 /* mobitool */, + 154306531CB78A3D006AB398 /* mobimeta */, + 157BEA6C2747BEDA004984B8 /* mobidrm */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 150039B718E06BC100D33077 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1550ADCE18E4B925006F9257 /* compression.c in Sources */, + 15EA81DF1A14D5AC00138554 /* structure.c in Sources */, + 1563314718EC36A200D4B858 /* debug.c in Sources */, + 15F1A1D118F4192D009CFE05 /* util.c in Sources */, + 1502448F1CD3A18F0075F4EC /* sha1.c in Sources */, + 15603889192D2E1A002EDB1A /* opf.c in Sources */, + 150A318D18E19BF9001A7AD7 /* write.c in Sources */, + 1550ADC318E427D7006F9257 /* buffer.c in Sources */, + 1553330118E359AE00334E23 /* read.c in Sources */, + 157DF7AD191A514D00191502 /* index.c in Sources */, + 153D91DB18E9630000E807B6 /* memory.c in Sources */, + 156AA65D1C81A3860085335A /* xmlwriter.c in Sources */, + 15AB2CB419572C2800EB7F74 /* parse_rawml.c in Sources */, + 152FD1E7270509A900AF276A /* randombytes.c in Sources */, + 15FB2BB21A1A32970052D5C5 /* encryption.c in Sources */, + 1504FD851CBE880B002AA042 /* meta.c in Sources */, + 151A46661909312900FAF3F4 /* miniz.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 154306501CB78A3D006AB398 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 154C2D411CC64A170041DD0E /* common.c in Sources */, + 1543065B1CB78A45006AB398 /* mobimeta.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1553331218E37F7000334E23 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 154C2D401CC64A170041DD0E /* common.c in Sources */, + 15615F0818F58C85004EBB6E /* mobitool.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 157BEA6F2747BEDA004984B8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 157BEA8A2747BF26004984B8 /* common.c in Sources */, + 157BEA852747BF13004984B8 /* mobidrm.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 1543065D1CB78B78006AB398 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 150039BA18E06BC100D33077 /* mobi */; + targetProxy = 1543065C1CB78B78006AB398 /* PBXContainerItemProxy */; + }; + 1553332018E37FB800334E23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 150039BA18E06BC100D33077 /* mobi */; + targetProxy = 1553331F18E37FB800334E23 /* PBXContainerItemProxy */; + }; + 157BEA6D2747BEDA004984B8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 150039BA18E06BC100D33077 /* mobi */; + targetProxy = 157BEA6E2747BEDA004984B8 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 150039BD18E06BC100D33077 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_GCD_PERFORMANCE = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LIBRARY = "compiler-default"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = NO; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_COMPLETION_HANDLER_MISUSE = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = "compiler-default"; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + /usr/include/libxml2, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "-DHAVE_CONFIG_H", + "-DHAVE_STRDUP", + ); + OTHER_LDFLAGS = "-lz"; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Debug; + }; + 150039BE18E06BC100D33077 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_GCD_PERFORMANCE = YES; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LIBRARY = "compiler-default"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = NO; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_COMPLETION_HANDLER_MISUSE = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = "compiler-default"; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_PEDANTIC = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + /usr/include/libxml2, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + ONLY_ACTIVE_ARCH = NO; + OTHER_CFLAGS = ( + "-DHAVE_CONFIG_H", + "-DHAVE_STRDUP", + ); + OTHER_LDFLAGS = "-lz"; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Release; + }; + 150039C018E06BC100D33077 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; + EXECUTABLE_PREFIX = lib; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/libxml2, + ); + OTHER_CFLAGS = ( + "-DHAVE_CONFIG_H", + "-DHAVE_STRDUP", + ); + OTHER_LDFLAGS = ( + "-lxml2", + "-lz", + ); + PRODUCT_NAME = mobi; + }; + name = Debug; + }; + 150039C118E06BC100D33077 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; + EXECUTABLE_PREFIX = lib; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/libxml2, + ); + OTHER_LDFLAGS = ( + "-lxml2", + "-lz", + ); + PRODUCT_NAME = mobi; + }; + name = Release; + }; + 154306581CB78A3D006AB398 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + ./src, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 154306591CB78A3D006AB398 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = YES; + DEAD_CODE_STRIPPING = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + ./src, + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 1553331D18E37F7100334E23 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ./src; + "HEADER_SEARCH_PATHS[arch=*]" = ./src; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_NAME = mobitool; + }; + name = Debug; + }; + 1553331E18E37F7100334E23 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + FRAMEWORK_SEARCH_PATHS = ""; + HEADER_SEARCH_PATHS = ./src; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_NAME = mobitool; + }; + name = Release; + }; + 157BEA762747BEDA004984B8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ./src; + "HEADER_SEARCH_PATHS[arch=*]" = ./src; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 157BEA772747BEDA004984B8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + FRAMEWORK_SEARCH_PATHS = ""; + HEADER_SEARCH_PATHS = ./src; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 150039B618E06BC100D33077 /* Build configuration list for PBXProject "mobi" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 150039BD18E06BC100D33077 /* Debug */, + 150039BE18E06BC100D33077 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 150039BF18E06BC100D33077 /* Build configuration list for PBXNativeTarget "mobi" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 150039C018E06BC100D33077 /* Debug */, + 150039C118E06BC100D33077 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1543065A1CB78A3D006AB398 /* Build configuration list for PBXNativeTarget "mobimeta" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 154306581CB78A3D006AB398 /* Debug */, + 154306591CB78A3D006AB398 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1553331C18E37F7100334E23 /* Build configuration list for PBXNativeTarget "mobitool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1553331D18E37F7100334E23 /* Debug */, + 1553331E18E37F7100334E23 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 157BEA752747BEDA004984B8 /* Build configuration list for PBXNativeTarget "mobidrm" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 157BEA762747BEDA004984B8 /* Debug */, + 157BEA772747BEDA004984B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 150039B318E06BC100D33077 /* Project object */; +} diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi.sln b/Charcoal/Charcoal/libmobi-public/msvc/libmobi.sln new file mode 100644 index 0000000..21a1863 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/libmobi.sln @@ -0,0 +1,97 @@ +īģŋ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmobi", "libmobi.vcxproj", "{A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mobidrm", "mobidrm\mobidrm.vcxproj", "{288A84A9-2AFD-4995-A397-E4554C8087AE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mobitool", "mobitool\mobitool.vcxproj", "{D8E9C708-FBD0-400C-B5B6-F8555FDE8767}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mobimeta", "mobimeta\mobimeta.vcxproj", "{2790D05E-6891-48E5-8450-F8D030763AD6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + NoDependenciesDebug|x64 = NoDependenciesDebug|x64 + NoDependenciesDebug|x86 = NoDependenciesDebug|x86 + NoDependenciesRelease|x64 = NoDependenciesRelease|x64 + NoDependenciesRelease|x86 = NoDependenciesRelease|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Debug|x64.ActiveCfg = Debug|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Debug|x64.Build.0 = Debug|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Debug|x86.ActiveCfg = Debug|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Debug|x86.Build.0 = Debug|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesDebug|x64.ActiveCfg = NoDependenciesDebug|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesDebug|x64.Build.0 = NoDependenciesDebug|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesDebug|x86.ActiveCfg = NoDependenciesDebug|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesDebug|x86.Build.0 = NoDependenciesDebug|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesRelease|x64.ActiveCfg = NoDependenciesRelease|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesRelease|x64.Build.0 = NoDependenciesRelease|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesRelease|x86.ActiveCfg = NoDependenciesRelease|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.NoDependenciesRelease|x86.Build.0 = NoDependenciesRelease|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Release|x64.ActiveCfg = Release|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Release|x64.Build.0 = Release|x64 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Release|x86.ActiveCfg = Release|Win32 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F}.Release|x86.Build.0 = Release|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Debug|x64.ActiveCfg = Debug|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Debug|x64.Build.0 = Debug|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Debug|x86.ActiveCfg = Debug|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Debug|x86.Build.0 = Debug|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesDebug|x64.ActiveCfg = Debug|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesDebug|x64.Build.0 = Debug|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesDebug|x86.ActiveCfg = Debug|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesDebug|x86.Build.0 = Debug|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesRelease|x64.ActiveCfg = Release|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesRelease|x64.Build.0 = Release|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesRelease|x86.ActiveCfg = Release|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.NoDependenciesRelease|x86.Build.0 = Release|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Release|x64.ActiveCfg = Release|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Release|x64.Build.0 = Release|x64 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Release|x86.ActiveCfg = Release|Win32 + {288A84A9-2AFD-4995-A397-E4554C8087AE}.Release|x86.Build.0 = Release|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Debug|x64.ActiveCfg = Debug|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Debug|x64.Build.0 = Debug|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Debug|x86.ActiveCfg = Debug|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Debug|x86.Build.0 = Debug|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesDebug|x64.ActiveCfg = Debug|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesDebug|x64.Build.0 = Debug|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesDebug|x86.ActiveCfg = Debug|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesDebug|x86.Build.0 = Debug|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesRelease|x64.ActiveCfg = Release|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesRelease|x64.Build.0 = Release|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesRelease|x86.ActiveCfg = Release|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.NoDependenciesRelease|x86.Build.0 = Release|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Release|x64.ActiveCfg = Release|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Release|x64.Build.0 = Release|x64 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Release|x86.ActiveCfg = Release|Win32 + {D8E9C708-FBD0-400C-B5B6-F8555FDE8767}.Release|x86.Build.0 = Release|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Debug|x64.ActiveCfg = Debug|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Debug|x64.Build.0 = Debug|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Debug|x86.ActiveCfg = Debug|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Debug|x86.Build.0 = Debug|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesDebug|x64.ActiveCfg = Debug|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesDebug|x64.Build.0 = Debug|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesDebug|x86.ActiveCfg = Debug|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesDebug|x86.Build.0 = Debug|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesRelease|x64.ActiveCfg = Release|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesRelease|x64.Build.0 = Release|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesRelease|x86.ActiveCfg = Release|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.NoDependenciesRelease|x86.Build.0 = Release|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Release|x64.ActiveCfg = Release|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Release|x64.Build.0 = Release|x64 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Release|x86.ActiveCfg = Release|Win32 + {2790D05E-6891-48E5-8450-F8D030763AD6}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {673B11AC-E877-465E-89D0-97CAA6C1B389} + EndGlobalSection +EndGlobal diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi.vcxproj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi.vcxproj new file mode 100644 index 0000000..5fb7551 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/libmobi.vcxproj @@ -0,0 +1,395 @@ + + + + + Debug + Win32 + + + NoDependenciesDebug + Win32 + + + NoDependenciesDebug + x64 + + + NoDependenciesRelease + Win32 + + + NoDependenciesRelease + x64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + {A48F597C-ADBC-499E-B282-0F8A2B1A4B5F} + Win32Proj + 10.0 + + + + StaticLibrary + true + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + false + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + true + v143 + + + StaticLibrary + false + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + static + + + true + static + + + true + static + + + true + static + + + static + + + static + + + static + + + static + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;MOBI_DEBUG=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + Level3 + ProgramDatabase + Disabled + + + MachineX86 + true + Windows + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;MOBI_DEBUG=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + Level3 + ProgramDatabase + Disabled + + + MachineX86 + true + Windows + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + Level3 + ProgramDatabase + MaxSpeed + Default + MultiThreadedDLL + false + + + MachineX86 + true + Windows + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + Level3 + ProgramDatabase + + + MachineX86 + true + Windows + true + true + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;MOBI_DEBUG=1;%(PreprocessorDefinitions) + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;MOBI_DEBUG=1;%(PreprocessorDefinitions) + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + ProgramDatabase + MaxSpeed + false + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + + HAVE_CONFIG_H;USE_XMLWRITER;USE_ENCRYPTION;%(PreprocessorDefinitions) + + + + + for /f "tokens=4 delims=[]" %%a in ('type "$(SolutionDir)..\configure.ac" ^| find "AC_INIT"') do ( + set version=%%a +) +echo Compiling libmobi version %version% +echo #define PACKAGE_VERSION "%version%" > "$(SolutionDir)..\config.h" + + + + + + + + + + + + true + false + false + true + true + false + false + true + + + + + + + + + + + true + false + false + true + true + false + false + true + + + + + + + + + + + + + true + false + false + true + true + false + false + true + + + + + + + + + + + + true + false + false + true + true + false + false + true + + + + + true + true + true + true + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi.vcxproj.user b/Charcoal/Charcoal/libmobi-public/msvc/libmobi.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/libmobi.vcxproj.user @@ -0,0 +1,4 @@ +īģŋ + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/buffer.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/buffer.obj new file mode 100644 index 0000000..12b19d0 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/buffer.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/compression.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/compression.obj new file mode 100644 index 0000000..68e9cb1 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/compression.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/debug.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/debug.obj new file mode 100644 index 0000000..328686e Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/debug.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/encryption.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/encryption.obj new file mode 100644 index 0000000..e1cb2b4 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/encryption.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/index.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/index.obj new file mode 100644 index 0000000..86a7d49 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/index.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.Build.CppClean.log b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.Build.CppClean.log new file mode 100644 index 0000000..24ac4c7 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.Build.CppClean.log @@ -0,0 +1,25 @@ +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\libmobi.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\libmobi.idb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\write.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\util.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\structure.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\sha1.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\read.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\randombytes.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\parse_rawml.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\opf.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\meta.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\memory.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\index.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\encryption.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\debug.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\compression.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\buffer.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\libmobi.lib +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\cl.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\cl.items.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\cl.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\cl.write.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\lib-link.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\lib-link.write.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\libmobi\x64\debug\libmobi.tlog\lib.command.1.tlog diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.lib.recipe b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.lib.recipe new file mode 100644 index 0000000..a53f961 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.lib.recipe @@ -0,0 +1,7 @@ +īģŋ + + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.log b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.log new file mode 100644 index 0000000..0b47d5e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.log @@ -0,0 +1,18 @@ +īģŋ Compiling libmobi version 0.11 + buffer.c + compression.c + debug.c + encryption.c + index.c + memory.c + meta.c + opf.c + parse_rawml.c + randombytes.c + read.c + sha1.c + structure.c + util.c + write.c + Generating Code... + libmobi.vcxproj -> C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\libmobi.lib diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.vcxproj.FileListAbsolute.txt b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/libmobi.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/memory.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/memory.obj new file mode 100644 index 0000000..0409cea Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/memory.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/meta.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/meta.obj new file mode 100644 index 0000000..6d106f7 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/meta.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/opf.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/opf.obj new file mode 100644 index 0000000..1d00ad9 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/opf.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/parse_rawml.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/parse_rawml.obj new file mode 100644 index 0000000..0fa629f Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/parse_rawml.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/randombytes.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/randombytes.obj new file mode 100644 index 0000000..a3900ac Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/randombytes.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/read.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/read.obj new file mode 100644 index 0000000..5ba4d51 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/read.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/sha1.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/sha1.obj new file mode 100644 index 0000000..6c83022 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/sha1.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/structure.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/structure.obj new file mode 100644 index 0000000..952c7c1 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/structure.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/util.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/util.obj new file mode 100644 index 0000000..7bb64ae Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/util.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/write.obj b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/write.obj new file mode 100644 index 0000000..6e3c41e Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/libmobi/x64/Debug/write.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/mobidrm.vcxproj b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/mobidrm.vcxproj new file mode 100644 index 0000000..3257516 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/mobidrm.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + {a48f597c-adbc-499e-b282-0f8a2b1a4b5f} + + + + + + + 16.0 + Win32Proj + {288a84a9-2afd-4995-a397-e4554c8087ae} + mobidrm + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + static + + + static + + + static + + + static + + + + Level3 + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;MOBI_DEBUG=1;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmtd.lib + + + + + Level3 + true + true + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmt.lib + + + + + Level3 + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;MOBI_DEBUG=1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmtd.lib + + + + + Level3 + true + true + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmt.lib + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/packages.config b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/packages.config new file mode 100644 index 0000000..47f6f2c --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/packages.config @@ -0,0 +1,5 @@ +īģŋ + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/common.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/common.obj new file mode 100644 index 0000000..cd47ad4 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/common.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/getopt.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/getopt.obj new file mode 100644 index 0000000..723f366 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/getopt.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.Build.CppClean.log b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.Build.CppClean.log new file mode 100644 index 0000000..dfce41b --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.Build.CppClean.log @@ -0,0 +1,18 @@ +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\vc143.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\vc143.idb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\getopt.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\common.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobidrm.exe +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobidrm.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobidrm.lib +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobidrm.exp +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.ilk +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\cl.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\cl.items.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\cl.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\cl.write.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\link.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\link.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\link.secondary.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobidrm\x64\debug\mobidrm.tlog\link.write.1.tlog diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.exe.recipe b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.exe.recipe new file mode 100644 index 0000000..1bd30de --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.exe.recipe @@ -0,0 +1,11 @@ +īģŋ + + + + C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobidrm.exe + + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.ilk b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.ilk new file mode 100644 index 0000000..5748855 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.ilk differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.log b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.log new file mode 100644 index 0000000..6e25ee7 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.log @@ -0,0 +1,8 @@ +īģŋ common.c + mobidrm.c + getopt.c + Generating Code... + Creating library C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobidrm.lib and object C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobidrm.exp + mobidrm.vcxproj -> C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobidrm.exe + 'pwsh.exe' is not recognized as an internal or external command, + operable program or batch file. diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.obj new file mode 100644 index 0000000..8bdb464 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.vcxproj.FileListAbsolute.txt b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/mobidrm.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vc143.idb b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vc143.idb new file mode 100644 index 0000000..c247a1a Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vc143.idb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vc143.pdb b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vc143.pdb new file mode 100644 index 0000000..9f170d0 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vc143.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vcpkg.applocal.log b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vcpkg.applocal.log new file mode 100644 index 0000000..e02abfc --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobidrm/x64/Debug/vcpkg.applocal.log @@ -0,0 +1 @@ +īģŋ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/mobimeta.vcxproj b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/mobimeta.vcxproj new file mode 100644 index 0000000..ea6137e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/mobimeta.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + {a48f597c-adbc-499e-b282-0f8a2b1a4b5f} + + + + + + + 16.0 + Win32Proj + {2790d05e-6891-48e5-8450-f8d030763ad6} + mobimeta + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + static + + + static + + + static + + + static + + + + Level3 + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;MOBI_DEBUG=1;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmtd.lib + + + + + Level3 + true + true + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmt.lib + + + + + Level3 + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;MOBI_DEBUG=1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmtd.lib + + + + + Level3 + true + true + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmt.lib + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/packages.config b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/packages.config new file mode 100644 index 0000000..47f6f2c --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/packages.config @@ -0,0 +1,5 @@ +īģŋ + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/common.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/common.obj new file mode 100644 index 0000000..9931926 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/common.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/getopt.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/getopt.obj new file mode 100644 index 0000000..a03dd50 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/getopt.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.Build.CppClean.log b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.Build.CppClean.log new file mode 100644 index 0000000..63d4268 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.Build.CppClean.log @@ -0,0 +1,18 @@ +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\vc143.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\vc143.idb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\getopt.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\common.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobimeta.exe +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobimeta.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobimeta.lib +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobimeta.exp +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.ilk +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\cl.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\cl.items.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\cl.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\cl.write.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\link.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\link.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\link.secondary.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobimeta\x64\debug\mobimeta.tlog\link.write.1.tlog diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.exe.recipe b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.exe.recipe new file mode 100644 index 0000000..d3255c7 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.exe.recipe @@ -0,0 +1,11 @@ +īģŋ + + + + C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobimeta.exe + + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.ilk b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.ilk new file mode 100644 index 0000000..22fd2a8 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.ilk differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.log b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.log new file mode 100644 index 0000000..316e1a6 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.log @@ -0,0 +1,8 @@ +īģŋ common.c + mobimeta.c + getopt.c + Generating Code... + Creating library C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobimeta.lib and object C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobimeta.exp + mobimeta.vcxproj -> C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobimeta.exe + 'pwsh.exe' is not recognized as an internal or external command, + operable program or batch file. diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.obj new file mode 100644 index 0000000..debbe23 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.vcxproj.FileListAbsolute.txt b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/mobimeta.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vc143.idb b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vc143.idb new file mode 100644 index 0000000..bd256db Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vc143.idb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vc143.pdb b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vc143.pdb new file mode 100644 index 0000000..337e943 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vc143.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vcpkg.applocal.log b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vcpkg.applocal.log new file mode 100644 index 0000000..e02abfc --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobimeta/x64/Debug/vcpkg.applocal.log @@ -0,0 +1 @@ +īģŋ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/mobitool.vcxproj b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/mobitool.vcxproj new file mode 100644 index 0000000..016a99e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/mobitool.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + {a48f597c-adbc-499e-b282-0f8a2b1a4b5f} + + + + + + + 16.0 + Win32Proj + {d8e9c708-fbd0-400c-b5b6-f8555fde8767} + mobitool + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + static + + + static + + + static + + + static + + + + Level3 + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;MOBI_DEBUG=1;MOBI_DEBUG=1WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmtd.lib + + + + + Level3 + true + true + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmt.lib + + + + + Level3 + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;MOBI_DEBUG=1;MOBI_DEBUG=1_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmtd.lib + + + + + Level3 + true + true + true + USE_XMLWRITER;USE_ENCRYPTION;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\..\src + + + Console + true + true + true + ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /NODEFAULTLIB:libcmt.lib + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/packages.config b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/packages.config new file mode 100644 index 0000000..47f6f2c --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/packages.config @@ -0,0 +1,5 @@ +īģŋ + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/common.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/common.obj new file mode 100644 index 0000000..0397601 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/common.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/getopt.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/getopt.obj new file mode 100644 index 0000000..b51c8db Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/getopt.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/miniz.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/miniz.obj new file mode 100644 index 0000000..dd5b49a Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/miniz.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.Build.CppClean.log b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.Build.CppClean.log new file mode 100644 index 0000000..95e2b17 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.Build.CppClean.log @@ -0,0 +1,19 @@ +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\vc143.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\vc143.idb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\getopt.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\common.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\miniz.obj +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobitool.exe +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobitool.pdb +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobitool.lib +c:\users\angel\onedrive\desktop\libmobi-public\msvc\x64\debug\mobitool.exp +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.ilk +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\cl.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\cl.items.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\cl.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\cl.write.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\link.command.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\link.read.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\link.secondary.1.tlog +c:\users\angel\onedrive\desktop\libmobi-public\msvc\mobitool\x64\debug\mobitool.tlog\link.write.1.tlog diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.exe.recipe b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.exe.recipe new file mode 100644 index 0000000..f386524 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.exe.recipe @@ -0,0 +1,11 @@ +īģŋ + + + + C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobitool.exe + + + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.ilk b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.ilk new file mode 100644 index 0000000..5057e4e Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.ilk differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.log b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.log new file mode 100644 index 0000000..ad16f7f --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.log @@ -0,0 +1,9 @@ +īģŋ miniz.c + common.c + mobitool.c + getopt.c + Generating Code... + Creating library C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobitool.lib and object C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobitool.exp + mobitool.vcxproj -> C:\Users\Angel\source\repos\Ebook-Image\Charcoal\Charcoal\libmobi-public\msvc\x64\Debug\mobitool.exe + 'pwsh.exe' is not recognized as an internal or external command, + operable program or batch file. diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.obj b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.obj new file mode 100644 index 0000000..6a6a094 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.obj differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.vcxproj.FileListAbsolute.txt b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/mobitool.vcxproj.FileListAbsolute.txt new file mode 100644 index 0000000..e69de29 diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vc143.idb b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vc143.idb new file mode 100644 index 0000000..2ede7ad Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vc143.idb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vc143.pdb b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vc143.pdb new file mode 100644 index 0000000..8dcf3b4 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vc143.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vcpkg.applocal.log b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vcpkg.applocal.log new file mode 100644 index 0000000..e02abfc --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/mobitool/x64/Debug/vcpkg.applocal.log @@ -0,0 +1 @@ +īģŋ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/packages.config b/Charcoal/Charcoal/libmobi-public/msvc/packages.config new file mode 100644 index 0000000..47f6f2c --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/msvc/packages.config @@ -0,0 +1,5 @@ +īģŋ + + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.idb b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.idb new file mode 100644 index 0000000..ab5730f Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.idb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.lib b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.lib new file mode 100644 index 0000000..4bf2dcd Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.lib differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.pdb b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.pdb new file mode 100644 index 0000000..15107a5 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/libmobi.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.exe b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.exe new file mode 100644 index 0000000..2e38e73 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.exe differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.exp b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.exp new file mode 100644 index 0000000..8bc6916 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.exp differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.lib b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.lib new file mode 100644 index 0000000..3e21ff4 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.lib differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.pdb b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.pdb new file mode 100644 index 0000000..05894d8 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobidrm.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.exe b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.exe new file mode 100644 index 0000000..79dd77f Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.exe differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.exp b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.exp new file mode 100644 index 0000000..ad98ac3 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.exp differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.lib b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.lib new file mode 100644 index 0000000..26c9078 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.lib differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.pdb b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.pdb new file mode 100644 index 0000000..724e39a Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobimeta.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.exe b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.exe new file mode 100644 index 0000000..fe2b0c1 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.exe differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.exp b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.exp new file mode 100644 index 0000000..e304068 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.exp differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.lib b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.lib new file mode 100644 index 0000000..e90bb41 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.lib differ diff --git a/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.pdb b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.pdb new file mode 100644 index 0000000..e5aa3da Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/msvc/x64/Debug/mobitool.pdb differ diff --git a/Charcoal/Charcoal/libmobi-public/src/CMakeLists.txt b/Charcoal/Charcoal/libmobi-public/src/CMakeLists.txt new file mode 100644 index 0000000..879898d --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright (c) 2022 Bartek Fabiszewski +# http://www.fabiszewski.net +# +# This file is part of libmobi. +# Licensed under LGPL, either version 3, or any later. +# See + +set(mobi_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/buffer.c + ${CMAKE_CURRENT_SOURCE_DIR}/buffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/compression.c + ${CMAKE_CURRENT_SOURCE_DIR}/compression.h + ${CMAKE_CURRENT_SOURCE_DIR}/config.h + ${CMAKE_CURRENT_SOURCE_DIR}/debug.c + ${CMAKE_CURRENT_SOURCE_DIR}/debug.h + ${CMAKE_CURRENT_SOURCE_DIR}/index.c + ${CMAKE_CURRENT_SOURCE_DIR}/index.h + ${CMAKE_CURRENT_SOURCE_DIR}/memory.c + ${CMAKE_CURRENT_SOURCE_DIR}/memory.h + ${CMAKE_CURRENT_SOURCE_DIR}/meta.c + ${CMAKE_CURRENT_SOURCE_DIR}/meta.h + ${CMAKE_CURRENT_SOURCE_DIR}/mobi.h + ${CMAKE_CURRENT_SOURCE_DIR}/parse_rawml.c + ${CMAKE_CURRENT_SOURCE_DIR}/parse_rawml.h + ${CMAKE_CURRENT_SOURCE_DIR}/read.c + ${CMAKE_CURRENT_SOURCE_DIR}/read.h + ${CMAKE_CURRENT_SOURCE_DIR}/structure.c + ${CMAKE_CURRENT_SOURCE_DIR}/structure.h + ${CMAKE_CURRENT_SOURCE_DIR}/util.c + ${CMAKE_CURRENT_SOURCE_DIR}/util.h + ${CMAKE_CURRENT_SOURCE_DIR}/write.c + ${CMAKE_CURRENT_SOURCE_DIR}/write.h + ${CMAKE_CURRENT_SOURCE_DIR}/xmlwriter.c + ${CMAKE_CURRENT_SOURCE_DIR}/xmlwriter.h +) + +if(USE_ENCRYPTION) + list(APPEND mobi_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/encryption.c + ${CMAKE_CURRENT_SOURCE_DIR}/encryption.h + ${CMAKE_CURRENT_SOURCE_DIR}/sha1.c + ${CMAKE_CURRENT_SOURCE_DIR}/sha1.h + ${CMAKE_CURRENT_SOURCE_DIR}/randombytes.c + ${CMAKE_CURRENT_SOURCE_DIR}/randombytes.h) +endif(USE_ENCRYPTION) + +if(USE_XMLWRITER) + list(APPEND mobi_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/opf.c + ${CMAKE_CURRENT_SOURCE_DIR}/opf.h) + if(NOT USE_LIBXML2) + list(APPEND mobi_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/xmlwriter.c + ${CMAKE_CURRENT_SOURCE_DIR}/xmlwriter.h) + endif(NOT USE_LIBXML2) +endif(USE_XMLWRITER) + + +add_library(mobi ${mobi_SOURCES}) + +set_target_properties(mobi PROPERTIES + OUTPUT_NAME "mobi" + SOVERSION ${PACKAGE_VERSION_MAJOR} + VERSION "${PACKAGE_VERSION}" + POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} + C_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + MACOSX_RPATH 1) + +if(USE_MINIZ) + set(miniz_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/miniz.c + ${CMAKE_CURRENT_SOURCE_DIR}/miniz.h + ) + add_library(miniz OBJECT ${miniz_SOURCES}) + target_compile_definitions(miniz PRIVATE + MINIZ_NO_STDIO + MINIZ_NO_ZLIB_COMPATIBLE_NAMES + MINIZ_NO_TIME + MINIZ_NO_ARCHIVE_APIS + MINIZ_NO_ARCHIVE_WRITING_APIS + _POSIX_C_SOURCE=200112L) + target_link_libraries(mobi PRIVATE miniz) +endif(USE_MINIZ) + +if(USE_LIBXML2) + target_link_libraries(mobi PUBLIC LibXml2::LibXml2) +endif(USE_LIBXML2) + +if(USE_ZLIB) + target_link_libraries(mobi PUBLIC ZLIB::ZLIB) +endif(USE_ZLIB) diff --git a/Charcoal/Charcoal/libmobi-public/src/Makefile.am b/Charcoal/Charcoal/libmobi-public/src/Makefile.am new file mode 100644 index 0000000..14b89f5 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/Makefile.am @@ -0,0 +1,27 @@ +# libmobi + +lib_LTLIBRARIES = libmobi.la +libmobi_la_SOURCES = buffer.c buffer.h compression.c compression.h config.h debug.c debug.h index.c index.h memory.c memory.h \ +meta.c meta.h parse_rawml.c parse_rawml.h read.c read.h structure.c structure.h util.c util.h write.c write.h + +if USE_XMLWRITER +libmobi_la_SOURCES += opf.c opf.h +if !USE_LIBXML2 +libmobi_la_SOURCES += xmlwriter.c xmlwriter.h +endif +endif +if USE_ENCRYPTION +libmobi_la_SOURCES += encryption.c encryption.h randombytes.c randombytes.h sha1.c sha1.h +endif +EXTRA_LTLIBRARIES = libminiz.la +libminiz_la_SOURCES = miniz.c miniz.h +libminiz_la_CFLAGS = $(VISIBILITY_HIDDEN) $(MINIZ_CFLAGS) \ +-DMINIZ_NO_STDIO -DMINIZ_NO_ZLIB_COMPATIBLE_NAMES \ +-DMINIZ_NO_TIME -DMINIZ_NO_ARCHIVE_APIS -DMINIZ_NO_ARCHIVE_WRITING_APIS +libminiz_la_LDFLAGS = +if USE_MINIZ +libmobi_la_LIBADD = libminiz.la +endif +include_HEADERS = mobi.h +libmobi_la_LDFLAGS = $(AVOID_VERSION) $(NO_UNDEFINED) $(DARWIN_LDFLAGS) $(LIBZ_LDFLAGS) $(LIBXML2_LDFLAGS) +libmobi_la_CFLAGS = $(VISIBILITY_HIDDEN) $(ISO99_SOURCE) $(DEBUG_CFLAGS) $(LIBXML2_CFLAGS) diff --git a/Charcoal/Charcoal/libmobi-public/src/README.md b/Charcoal/Charcoal/libmobi-public/src/README.md new file mode 100644 index 0000000..6f89e68 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/README.md @@ -0,0 +1,51 @@ +## mobitool + usage: /Users/baf/src/libmobi/tools/.libs/mobitool [-cdehimrstuvx7] [-o dir] [-p pid] [-P serial] filename + without arguments prints document metadata and exits + -c dump cover + -d dump rawml text record + -e create EPUB file (with -s will dump EPUB source) + -h show this usage summary and exit + -i print detailed metadata + -m print records metadata + -o dir save output to dir folder + -p pid set pid for decryption + -P serial set device serial for decryption + -r dump raw records + -s dump recreated source files + -t split hybrid file into two parts + -u show rusage + -v show version and exit + -x extract conversion source and log (if present) + -7 parse KF7 part of hybrid file (by default KF8 part is parsed) + +## mobimeta + usage: mobimeta [-a | -s meta=value[,meta=value,...]] [-d meta[,meta,...]] [-p pid] [-P serial] [-hv] filein [fileout] + without arguments prints document metadata and exits + -a ? list valid meta named keys + -a meta=value add metadata + -d meta delete metadata + -s meta=value set metadata + -p pid set pid for decryption + -P serial set device serial for decryption + -h show this usage summary and exit + -v show version and exit + +## mobidrm + usage: mobidrm [-d | -e] [-hv] [-p pid] [-f date] [-t date] [-s serial] [-o dir] filename + without arguments prints document metadata and exits + + Decrypt options: + -d decrypt (required) + -p pid set decryption pid (may be specified multiple times) + -s serial set device serial (may be specified multiple times) + + Encrypt options: + -e encrypt (required) + -s serial set device serial (may be specified multiple times) + -f date set validity period from date (yyyy-mm-dd) when encrypting (inclusive) + -t date set validity period to date (yyyy-mm-dd) when encrypting (inclusive) + + Common options: + -o dir save output to dir folder + -h show this usage summary and exit + -v show version and exit diff --git a/Charcoal/Charcoal/libmobi-public/src/buffer - Copy.c b/Charcoal/Charcoal/libmobi-public/src/buffer - Copy.c new file mode 100644 index 0000000..d469187 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/buffer - Copy.c @@ -0,0 +1,637 @@ +/** @file buffer.c + * @brief Functions to read/write raw big endian data + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include "buffer.h" +#include "debug.h" + +/** + @brief Initializer for MOBIBuffer structure + + It allocates memory for structure and for data. + Memory should be freed with mobi_buffer_free(). + + @param[in] len Size of data to be allocated for the buffer + @return MOBIBuffer on success, NULL otherwise + */ +MOBIBuffer * mobi_buffer_init(const size_t len) { + unsigned char *data = malloc(len); + if (data == NULL) { + debug_print("%s", "Buffer data allocation failed\n"); + return NULL; + } + MOBIBuffer *buf = mobi_buffer_init_null(data, len); + if (buf == NULL) { + free(data); + } + return buf; +} + +/** + @brief Initializer for MOBIBuffer structure + + It allocates memory for structure but, unlike mobi_buffer_init(), it does not allocate memory for data. + Instead it works on external data. + Memory should be freed with mobi_buffer_free_null() (buf->data will not be deallocated). + + @param[in,out] data Set data as buffer data + @param[in] len Size of data held by the buffer + @return MOBIBuffer on success, NULL otherwise + */ +MOBIBuffer * mobi_buffer_init_null(unsigned char *data, const size_t len) { + MOBIBuffer *buf = malloc(sizeof(MOBIBuffer)); + if (buf == NULL) { + debug_print("%s", "Buffer allocation failed\n"); + return NULL; + } + buf->data = data; + buf->offset = 0; + buf->maxlen = len; + buf->error = MOBI_SUCCESS; + return buf; +} + +/** + @brief Resize buffer + + Smaller size than offset will cause data truncation. + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] newlen New buffer size + */ +void mobi_buffer_resize(MOBIBuffer *buf, const size_t newlen) { + unsigned char *tmp = realloc(buf->data, newlen); + if (tmp == NULL) { + debug_print("%s", "Buffer allocation failed\n"); + buf->error = MOBI_MALLOC_FAILED; + return; + } + buf->data = tmp; + buf->maxlen = newlen; + if (buf->offset >= newlen) { + buf->offset = newlen - 1; + } + debug_print("Buffer successfully resized to %zu\n", newlen); + buf->error = MOBI_SUCCESS; +} + +/** + @brief Adds 8-bit value to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Integer to be put into the buffer + */ +void mobi_buffer_add8(MOBIBuffer *buf, const uint8_t data) { + if (buf->offset + 1 > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + buf->data[buf->offset++] = data; +} + +/** + @brief Adds 16-bit value to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Integer to be put into the buffer + */ +void mobi_buffer_add16(MOBIBuffer *buf, const uint16_t data) { + if (buf->offset + 2 > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + unsigned char *buftr = buf->data + buf->offset; + *buftr++ = (uint8_t)((uint32_t)(data & 0xff00U) >> 8); + *buftr = (uint8_t)((uint32_t)(data & 0xffU)); + buf->offset += 2; +} + +/** + @brief Adds 32-bit value to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Integer to be put into the buffer + */ +void mobi_buffer_add32(MOBIBuffer *buf, const uint32_t data) { + if (buf->offset + 4 > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + unsigned char *buftr = buf->data + buf->offset; + *buftr++ = (uint8_t)((uint32_t)(data & 0xff000000U) >> 24); + *buftr++ = (uint8_t)((uint32_t)(data & 0xff0000U) >> 16); + *buftr++ = (uint8_t)((uint32_t)(data & 0xff00U) >> 8); + *buftr = (uint8_t)((uint32_t)(data & 0xffU)); + buf->offset += 4; +} + +/** + @brief Adds raw data to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Pointer to read data + @param[in] len Size of the read data + */ +void mobi_buffer_addraw(MOBIBuffer *buf, const unsigned char* data, const size_t len) { + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + memcpy(buf->data + buf->offset, data, len); + buf->offset += len; +} + +/** + @brief Adds string to MOBIBuffer without null terminator + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] str Pointer to string + */ +void mobi_buffer_addstring(MOBIBuffer *buf, const char *str) { + const size_t len = strlen(str); + mobi_buffer_addraw(buf, (const unsigned char *) str, len); +} + +/** + @brief Adds count of zeroes to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] count Number of zeroes to be put into the buffer + */ +void mobi_buffer_addzeros(MOBIBuffer *buf, const size_t count) { + if (buf->offset + count > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + memset(buf->data + buf->offset, 0, count); + buf->offset += count; +} + +/** + @brief Reads 8-bit value from MOBIBuffer + + @param[in] buf MOBIBuffer structure containing data + @return Read value, 0 if end of buffer is encountered + */ +uint8_t mobi_buffer_get8(MOBIBuffer *buf) { + if (buf->offset + 1 > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + return buf->data[buf->offset++]; +} + +/** + @brief Reads 16-bit value from MOBIBuffer + + @param[in] buf MOBIBuffer structure containing data + @return Read value, 0 if end of buffer is encountered + */ +uint16_t mobi_buffer_get16(MOBIBuffer *buf) { + if (buf->offset + 2 > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + uint16_t val; + val = (uint16_t)((uint16_t) buf->data[buf->offset] << 8 | (uint16_t) buf->data[buf->offset + 1]); + buf->offset += 2; + return val; +} + +/** + @brief Reads 32-bit value from MOBIBuffer + + @param[in] buf MOBIBuffer structure containing data + @return Read value, 0 if end of buffer is encountered + */ +uint32_t mobi_buffer_get32(MOBIBuffer *buf) { + if (buf->offset + 4 > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + uint32_t val; + val = (uint32_t) buf->data[buf->offset] << 24 | (uint32_t) buf->data[buf->offset + 1] << 16 | (uint32_t) buf->data[buf->offset + 2] << 8 | (uint32_t) buf->data[buf->offset + 3]; + buf->offset += 4; + return val; +} + +/** + @brief Reads variable length value from MOBIBuffer + + Internal function for wrappers: + mobi_buffer_get_varlen(); + mobi_buffer_get_varlen_dec(); + + Reads maximum 4 bytes from the buffer. Stops when byte has bit 7 set. + + This function has a limitation while reading backwards. + In such case it will not read first byte in a buffer, as it would cause buffer offset to underflow. + That means that going bacwards it cannot read variable length values that are placed at the beginning of a buffer. + This will result in an error. + + @param[in] buf MOBIBuffer structure containing data + @param[out] len Value will be increased by number of bytes read + @param[in] direction 1 - read buffer forward, -1 - read buffer backwards + @return Read value, 0 if end of buffer is encountered + */ +static uint32_t mobi_buffer_get_varlen_internal(MOBIBuffer *buf, size_t *len, const int direction) { + bool has_stop = false; + uint32_t val = 0; + uint8_t byte_count = 0; + size_t max_count = direction == 1 ? buf->maxlen - buf->offset : buf->offset; + if (buf->offset < buf->maxlen && max_count) { + max_count = max_count < 4 ? max_count : 4; + uint8_t byte; + const uint8_t stop_flag = 0x80; + const uint8_t mask = 0x7f; + uint32_t shift = 0; + unsigned char *p = buf->data + buf->offset; + do { + if (direction == 1) { + byte = *p++; + val <<= 7; + val |= (byte & mask); + } else { + byte = *p--; + val = val | (uint32_t)(byte & mask) << shift; + shift += 7; + } + byte_count++; + has_stop = byte & stop_flag; + } while (!has_stop && (byte_count < max_count)); + } + if (!has_stop) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + *len += byte_count; + buf->offset = direction == 1 ? buf->offset + byte_count : buf->offset - byte_count; + return val; +} + +/** + @brief Reads variable length value from MOBIBuffer + + Reads maximum 4 bytes from the buffer. Stops when byte has bit 7 set. + + @param[in] buf MOBIBuffer structure containing data + @param[out] len Value will be increased by number of bytes read + @return Read value, 0 if end of buffer is encountered + */ +uint32_t mobi_buffer_get_varlen(MOBIBuffer *buf, size_t *len) { + return mobi_buffer_get_varlen_internal(buf, len, 1); +} + +/** + @brief Reads variable length value from MOBIBuffer going backwards + + Reads maximum 4 bytes from the buffer. Stops when byte has bit 7 set. + + This function has a limitation. It will not read first byte in a buffer, as it would cause buffer offset to underflow. + That means that it cannot read variable length values that are placed at the beginning of a buffer. + This will result in an error. + + @param[in] buf MOBIBuffer structure containing data + @param[out] len Value will be increased by number of bytes read + @return Read value, 0 if end of buffer is encountered + */ +uint32_t mobi_buffer_get_varlen_dec(MOBIBuffer *buf, size_t *len) { + return mobi_buffer_get_varlen_internal(buf, len, -1); +} + +/** + @brief Reads raw data from MOBIBuffer and pads it with zero character + + @param[out] str Destination for string read from buffer. Length must be (len + 1) + @param[in] buf MOBIBuffer structure containing data + @param[in] len Length of the data to be read from buffer + */ +void mobi_buffer_getstring(char *str, MOBIBuffer *buf, const size_t len) { + if (!str) { + buf->error = MOBI_PARAM_ERR; + return; + } + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + str[0] = '\0'; + return; + } + memcpy(str, buf->data + buf->offset, len); + str[len] = '\0'; + buf->offset += len; +} + +/** + @brief Reads raw data from MOBIBuffer, appends it to a string and pads it with zero character + + @param[in,out] str A string to which data will be appended + @param[in] buf MOBIBuffer structure containing data + @param[in] len Length of the data to be read from buffer + */ +void mobi_buffer_appendstring(char *str, MOBIBuffer *buf, const size_t len) { + if (!str) { + buf->error = MOBI_PARAM_ERR; + return; + } + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + size_t str_len = strlen(str); + memcpy(str + str_len, buf->data + buf->offset, len); + str[str_len + len] = '\0'; + buf->offset += len; +} + +/** + @brief Reads raw data from MOBIBuffer + + @param[out] data Destination to which data will be appended + @param[in] buf MOBIBuffer structure containing data + @param[in] len Length of the data to be read from buffer + */ +void mobi_buffer_getraw(void *data, MOBIBuffer *buf, const size_t len) { + if (!data) { + buf->error = MOBI_PARAM_ERR; + return; + } + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + memcpy(data, buf->data + buf->offset, len); + buf->offset += len; +} + +/** + @brief Get pointer to MOBIBuffer data at offset + + @param[in] buf MOBIBuffer structure containing data + @param[in] len Check if requested length is available in buffer + @return Pointer to offset, or NULL on failure + */ +unsigned char * mobi_buffer_getpointer(MOBIBuffer *buf, const size_t len) { + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return NULL; + } + buf->offset += len; + return buf->data + buf->offset - len; +} + +/** + @brief Read 8-bit value from MOBIBuffer into allocated memory + + Read 8-bit value from buffer into memory allocated by the function. + Returns pointer to the value, which must be freed later. + If the data is not accessible function will return null pointer. + + @param[out] val Pointer to value or null pointer on failure + @param[in] buf MOBIBuffer structure containing data + */ +void mobi_buffer_dup8(uint8_t **val, MOBIBuffer *buf) { + *val = NULL; + if (buf->offset + 1 > buf->maxlen) { + return; + } + *val = malloc(sizeof(uint8_t)); + if (*val == NULL) { + return; + } + **val = mobi_buffer_get8(buf); +} + +/** + @brief Read 16-bit value from MOBIBuffer into allocated memory + + Read 16-bit value from buffer into allocated memory. + Returns pointer to the value, which must be freed later. + If the data is not accessible function will return null pointer. + + @param[out] val Pointer to value or null pointer on failure + @param[in] buf MOBIBuffer structure containing data + */ +void mobi_buffer_dup16(uint16_t **val, MOBIBuffer *buf) { + *val = NULL; + if (buf->offset + 2 > buf->maxlen) { + return; + } + *val = malloc(sizeof(uint16_t)); + if (*val == NULL) { + return; + } + **val = mobi_buffer_get16(buf); +} + +/** + @brief Read 32-bit value from MOBIBuffer into allocated memory + + Read 32-bit value from buffer into allocated memory. + Returns pointer to the value, which must be freed later. + If the data is not accessible function will return null pointer. + + @param[out] val Pointer to value + @param[in] buf MOBIBuffer structure containing data + */ +void mobi_buffer_dup32(uint32_t **val, MOBIBuffer *buf) { + *val = NULL; + if (buf->offset + 4 > buf->maxlen) { + return; + } + *val = malloc(sizeof(uint32_t)); + if (*val == NULL) { + return; + } + **val = mobi_buffer_get32(buf); +} + +/** + @brief Copy 8-bit value from one MOBIBuffer into another + + @param[out] dest Destination buffer + @param[in] source Source buffer + */ +void mobi_buffer_copy8(MOBIBuffer *dest, MOBIBuffer *source) { + mobi_buffer_add8(dest, mobi_buffer_get8(source)); +} + +/** + @brief Copy raw value from one MOBIBuffer into another + + @param[out] dest Destination buffer + @param[in] source Source buffer + @param[in] len Number of bytes to copy + */ +void mobi_buffer_copy(MOBIBuffer *dest, MOBIBuffer *source, const size_t len) { + if (source->offset + len > source->maxlen) { + debug_print("%s", "End of buffer\n"); + source->error = MOBI_BUFFER_END; + return; + } + if (dest->offset + len > dest->maxlen) { + debug_print("%s", "End of buffer\n"); + dest->error = MOBI_BUFFER_END; + return; + } + memcpy(dest->data + dest->offset, source->data + source->offset, len); + dest->offset += len; + source->offset += len; +} + +/** + @brief Copy raw value within one MOBIBuffer + + Memmove len bytes from offset (relative to current position) + to current position in buffer and advance buffer position. + Data may overlap. + + @param[out] buf Buffer + @param[in] offset Offset to read from + @param[in] len Number of bytes to copy + */ +void mobi_buffer_move(MOBIBuffer *buf, const int offset, const size_t len) { + size_t aoffset = (size_t) abs(offset); + unsigned char *source = buf->data + buf->offset; + if (offset >= 0) { + if (buf->offset + aoffset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + source += aoffset; + } else { + if ( (buf->offset < aoffset) || (buf->offset + len > buf->maxlen) ) { + debug_print("%s", "Beyond start/end of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + source -= aoffset; + } + memmove(buf->data + buf->offset, source, len); + buf->offset += len; +} + +/** + @brief Check if buffer data header contains magic signature + + @param[in] buf MOBIBuffer buffer containing data + @param[in] magic Magic signature + @return boolean true on match, false otherwise + */ +bool mobi_buffer_match_magic(MOBIBuffer *buf, const char *magic) { + const size_t magic_length = strlen(magic); + if (buf->offset + magic_length > buf->maxlen) { + return false; + } + if (memcmp(buf->data + buf->offset, magic, magic_length) == 0) { + return true; + } + return false; +} + +/** + @brief Check if buffer contains magic signature at given offset + + @param[in] buf MOBIBuffer buffer containing data + @param[in] magic Magic signature + @param[in] offset Offset + @return boolean true on match, false otherwise + */ +bool mobi_buffer_match_magic_offset(MOBIBuffer *buf, const char *magic, const size_t offset) { + bool match = false; + if (offset <= buf->maxlen) { + const size_t save_offset = buf->offset; + buf->offset = offset; + match = mobi_buffer_match_magic(buf, magic); + buf->offset = save_offset; + } + return match; +} + +/** + @brief Move current buffer offset by diff bytes + + @param[in,out] buf MOBIBuffer buffer containing data + @param[in] diff Number of bytes by which the offset is adjusted + */ +void mobi_buffer_seek(MOBIBuffer *buf, const int diff) { + size_t adiff = (size_t) abs(diff); + if (diff >= 0) { + if (buf->offset + adiff <= buf->maxlen) { + buf->offset += adiff; + return; + } + } else { + if (buf->offset >= adiff) { + buf->offset -= adiff; + return; + } + } + buf->error = MOBI_BUFFER_END; + debug_print("%s", "End of buffer\n"); +} + +/** + @brief Set buffer offset to pos position + + @param[in,out] buf MOBIBuffer buffer containing data + @param[in] pos New position + */ +void mobi_buffer_setpos(MOBIBuffer *buf, const size_t pos) { + if (pos <= buf->maxlen) { + buf->offset = pos; + return; + } + buf->error = MOBI_BUFFER_END; + debug_print("%s", "End of buffer\n"); +} + +/** + @brief Free pointer to MOBIBuffer structure and pointer to data + + Free data initialized with mobi_buffer_init(); + + @param[in] buf MOBIBuffer structure + */ +void mobi_buffer_free(MOBIBuffer *buf) { + if (buf == NULL) { return; } + if (buf->data != NULL) { + free(buf->data); + } + free(buf); +} + +/** + @brief Free pointer to MOBIBuffer structure + + Free data initialized with mobi_buffer_init_null(); + Unlike mobi_buffer_free() it will not free pointer to buf->data + + @param[in] buf MOBIBuffer structure + */ +void mobi_buffer_free_null(MOBIBuffer *buf) { + if (buf == NULL) { return; } + free(buf); +} diff --git a/Charcoal/Charcoal/libmobi-public/src/buffer - Copy.h b/Charcoal/Charcoal/libmobi-public/src/buffer - Copy.h new file mode 100644 index 0000000..eecff21 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/buffer - Copy.h @@ -0,0 +1,58 @@ +/** @file buffer.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_buffer_h +#define libmobi_buffer_h + +#include "config.h" +#include "mobi.h" + +/** + @brief Buffer to read to/write from + */ +typedef struct { + size_t offset; /**< Current offset in respect to buffer start */ + size_t maxlen; /**< Length of the buffer data */ + unsigned char *data; /**< Pointer to buffer data */ + MOBI_RET error; /**< MOBI_SUCCESS = 0 if operation on buffer is successful, non-zero value on failure */ +} MOBIBuffer; + +MOBIBuffer * mobi_buffer_init(const size_t len); +MOBIBuffer * mobi_buffer_init_null(unsigned char *data, const size_t len); +void mobi_buffer_resize(MOBIBuffer *buf, const size_t newlen); +void mobi_buffer_add8(MOBIBuffer *buf, const uint8_t data); +void mobi_buffer_add16(MOBIBuffer *buf, const uint16_t data); +void mobi_buffer_add32(MOBIBuffer *buf, const uint32_t data); +void mobi_buffer_addraw(MOBIBuffer *buf, const unsigned char* data, const size_t len); +void mobi_buffer_addstring(MOBIBuffer *buf, const char *str); +void mobi_buffer_addzeros(MOBIBuffer *buf, const size_t count); +uint8_t mobi_buffer_get8(MOBIBuffer *buf); +uint16_t mobi_buffer_get16(MOBIBuffer *buf); +uint32_t mobi_buffer_get32(MOBIBuffer *buf); +uint32_t mobi_buffer_get_varlen(MOBIBuffer *buf, size_t *len); +uint32_t mobi_buffer_get_varlen_dec(MOBIBuffer *buf, size_t *len); +void mobi_buffer_dup8(uint8_t **val, MOBIBuffer *buf); +void mobi_buffer_dup16(uint16_t **val, MOBIBuffer *buf); +void mobi_buffer_dup32(uint32_t **val, MOBIBuffer *buf); +void mobi_buffer_getstring(char *str, MOBIBuffer *buf, const size_t len); +void mobi_buffer_appendstring(char *str, MOBIBuffer *buf, const size_t len); +void mobi_buffer_getraw(void *data, MOBIBuffer *buf, const size_t len); +unsigned char * mobi_buffer_getpointer(MOBIBuffer *buf, const size_t len); +void mobi_buffer_copy8(MOBIBuffer *dest, MOBIBuffer *source); +void mobi_buffer_move(MOBIBuffer *buf, const int offset, const size_t len); +void mobi_buffer_copy(MOBIBuffer *dest, MOBIBuffer *source, const size_t len); +bool mobi_buffer_match_magic(MOBIBuffer *buf, const char *magic); +bool mobi_buffer_match_magic_offset(MOBIBuffer *buf, const char *magic, const size_t offset); +void mobi_buffer_seek(MOBIBuffer *buf, const int diff); +void mobi_buffer_setpos(MOBIBuffer *buf, const size_t pos); +void mobi_buffer_free(MOBIBuffer *buf); +void mobi_buffer_free_null(MOBIBuffer *buf); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/buffer.c b/Charcoal/Charcoal/libmobi-public/src/buffer.c new file mode 100644 index 0000000..d469187 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/buffer.c @@ -0,0 +1,637 @@ +/** @file buffer.c + * @brief Functions to read/write raw big endian data + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include "buffer.h" +#include "debug.h" + +/** + @brief Initializer for MOBIBuffer structure + + It allocates memory for structure and for data. + Memory should be freed with mobi_buffer_free(). + + @param[in] len Size of data to be allocated for the buffer + @return MOBIBuffer on success, NULL otherwise + */ +MOBIBuffer * mobi_buffer_init(const size_t len) { + unsigned char *data = malloc(len); + if (data == NULL) { + debug_print("%s", "Buffer data allocation failed\n"); + return NULL; + } + MOBIBuffer *buf = mobi_buffer_init_null(data, len); + if (buf == NULL) { + free(data); + } + return buf; +} + +/** + @brief Initializer for MOBIBuffer structure + + It allocates memory for structure but, unlike mobi_buffer_init(), it does not allocate memory for data. + Instead it works on external data. + Memory should be freed with mobi_buffer_free_null() (buf->data will not be deallocated). + + @param[in,out] data Set data as buffer data + @param[in] len Size of data held by the buffer + @return MOBIBuffer on success, NULL otherwise + */ +MOBIBuffer * mobi_buffer_init_null(unsigned char *data, const size_t len) { + MOBIBuffer *buf = malloc(sizeof(MOBIBuffer)); + if (buf == NULL) { + debug_print("%s", "Buffer allocation failed\n"); + return NULL; + } + buf->data = data; + buf->offset = 0; + buf->maxlen = len; + buf->error = MOBI_SUCCESS; + return buf; +} + +/** + @brief Resize buffer + + Smaller size than offset will cause data truncation. + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] newlen New buffer size + */ +void mobi_buffer_resize(MOBIBuffer *buf, const size_t newlen) { + unsigned char *tmp = realloc(buf->data, newlen); + if (tmp == NULL) { + debug_print("%s", "Buffer allocation failed\n"); + buf->error = MOBI_MALLOC_FAILED; + return; + } + buf->data = tmp; + buf->maxlen = newlen; + if (buf->offset >= newlen) { + buf->offset = newlen - 1; + } + debug_print("Buffer successfully resized to %zu\n", newlen); + buf->error = MOBI_SUCCESS; +} + +/** + @brief Adds 8-bit value to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Integer to be put into the buffer + */ +void mobi_buffer_add8(MOBIBuffer *buf, const uint8_t data) { + if (buf->offset + 1 > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + buf->data[buf->offset++] = data; +} + +/** + @brief Adds 16-bit value to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Integer to be put into the buffer + */ +void mobi_buffer_add16(MOBIBuffer *buf, const uint16_t data) { + if (buf->offset + 2 > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + unsigned char *buftr = buf->data + buf->offset; + *buftr++ = (uint8_t)((uint32_t)(data & 0xff00U) >> 8); + *buftr = (uint8_t)((uint32_t)(data & 0xffU)); + buf->offset += 2; +} + +/** + @brief Adds 32-bit value to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Integer to be put into the buffer + */ +void mobi_buffer_add32(MOBIBuffer *buf, const uint32_t data) { + if (buf->offset + 4 > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + unsigned char *buftr = buf->data + buf->offset; + *buftr++ = (uint8_t)((uint32_t)(data & 0xff000000U) >> 24); + *buftr++ = (uint8_t)((uint32_t)(data & 0xff0000U) >> 16); + *buftr++ = (uint8_t)((uint32_t)(data & 0xff00U) >> 8); + *buftr = (uint8_t)((uint32_t)(data & 0xffU)); + buf->offset += 4; +} + +/** + @brief Adds raw data to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] data Pointer to read data + @param[in] len Size of the read data + */ +void mobi_buffer_addraw(MOBIBuffer *buf, const unsigned char* data, const size_t len) { + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + memcpy(buf->data + buf->offset, data, len); + buf->offset += len; +} + +/** + @brief Adds string to MOBIBuffer without null terminator + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] str Pointer to string + */ +void mobi_buffer_addstring(MOBIBuffer *buf, const char *str) { + const size_t len = strlen(str); + mobi_buffer_addraw(buf, (const unsigned char *) str, len); +} + +/** + @brief Adds count of zeroes to MOBIBuffer + + @param[in,out] buf MOBIBuffer structure to be filled with data + @param[in] count Number of zeroes to be put into the buffer + */ +void mobi_buffer_addzeros(MOBIBuffer *buf, const size_t count) { + if (buf->offset + count > buf->maxlen) { + debug_print("%s", "Buffer full\n"); + buf->error = MOBI_BUFFER_END; + return; + } + memset(buf->data + buf->offset, 0, count); + buf->offset += count; +} + +/** + @brief Reads 8-bit value from MOBIBuffer + + @param[in] buf MOBIBuffer structure containing data + @return Read value, 0 if end of buffer is encountered + */ +uint8_t mobi_buffer_get8(MOBIBuffer *buf) { + if (buf->offset + 1 > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + return buf->data[buf->offset++]; +} + +/** + @brief Reads 16-bit value from MOBIBuffer + + @param[in] buf MOBIBuffer structure containing data + @return Read value, 0 if end of buffer is encountered + */ +uint16_t mobi_buffer_get16(MOBIBuffer *buf) { + if (buf->offset + 2 > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + uint16_t val; + val = (uint16_t)((uint16_t) buf->data[buf->offset] << 8 | (uint16_t) buf->data[buf->offset + 1]); + buf->offset += 2; + return val; +} + +/** + @brief Reads 32-bit value from MOBIBuffer + + @param[in] buf MOBIBuffer structure containing data + @return Read value, 0 if end of buffer is encountered + */ +uint32_t mobi_buffer_get32(MOBIBuffer *buf) { + if (buf->offset + 4 > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + uint32_t val; + val = (uint32_t) buf->data[buf->offset] << 24 | (uint32_t) buf->data[buf->offset + 1] << 16 | (uint32_t) buf->data[buf->offset + 2] << 8 | (uint32_t) buf->data[buf->offset + 3]; + buf->offset += 4; + return val; +} + +/** + @brief Reads variable length value from MOBIBuffer + + Internal function for wrappers: + mobi_buffer_get_varlen(); + mobi_buffer_get_varlen_dec(); + + Reads maximum 4 bytes from the buffer. Stops when byte has bit 7 set. + + This function has a limitation while reading backwards. + In such case it will not read first byte in a buffer, as it would cause buffer offset to underflow. + That means that going bacwards it cannot read variable length values that are placed at the beginning of a buffer. + This will result in an error. + + @param[in] buf MOBIBuffer structure containing data + @param[out] len Value will be increased by number of bytes read + @param[in] direction 1 - read buffer forward, -1 - read buffer backwards + @return Read value, 0 if end of buffer is encountered + */ +static uint32_t mobi_buffer_get_varlen_internal(MOBIBuffer *buf, size_t *len, const int direction) { + bool has_stop = false; + uint32_t val = 0; + uint8_t byte_count = 0; + size_t max_count = direction == 1 ? buf->maxlen - buf->offset : buf->offset; + if (buf->offset < buf->maxlen && max_count) { + max_count = max_count < 4 ? max_count : 4; + uint8_t byte; + const uint8_t stop_flag = 0x80; + const uint8_t mask = 0x7f; + uint32_t shift = 0; + unsigned char *p = buf->data + buf->offset; + do { + if (direction == 1) { + byte = *p++; + val <<= 7; + val |= (byte & mask); + } else { + byte = *p--; + val = val | (uint32_t)(byte & mask) << shift; + shift += 7; + } + byte_count++; + has_stop = byte & stop_flag; + } while (!has_stop && (byte_count < max_count)); + } + if (!has_stop) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + *len += byte_count; + buf->offset = direction == 1 ? buf->offset + byte_count : buf->offset - byte_count; + return val; +} + +/** + @brief Reads variable length value from MOBIBuffer + + Reads maximum 4 bytes from the buffer. Stops when byte has bit 7 set. + + @param[in] buf MOBIBuffer structure containing data + @param[out] len Value will be increased by number of bytes read + @return Read value, 0 if end of buffer is encountered + */ +uint32_t mobi_buffer_get_varlen(MOBIBuffer *buf, size_t *len) { + return mobi_buffer_get_varlen_internal(buf, len, 1); +} + +/** + @brief Reads variable length value from MOBIBuffer going backwards + + Reads maximum 4 bytes from the buffer. Stops when byte has bit 7 set. + + This function has a limitation. It will not read first byte in a buffer, as it would cause buffer offset to underflow. + That means that it cannot read variable length values that are placed at the beginning of a buffer. + This will result in an error. + + @param[in] buf MOBIBuffer structure containing data + @param[out] len Value will be increased by number of bytes read + @return Read value, 0 if end of buffer is encountered + */ +uint32_t mobi_buffer_get_varlen_dec(MOBIBuffer *buf, size_t *len) { + return mobi_buffer_get_varlen_internal(buf, len, -1); +} + +/** + @brief Reads raw data from MOBIBuffer and pads it with zero character + + @param[out] str Destination for string read from buffer. Length must be (len + 1) + @param[in] buf MOBIBuffer structure containing data + @param[in] len Length of the data to be read from buffer + */ +void mobi_buffer_getstring(char *str, MOBIBuffer *buf, const size_t len) { + if (!str) { + buf->error = MOBI_PARAM_ERR; + return; + } + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + str[0] = '\0'; + return; + } + memcpy(str, buf->data + buf->offset, len); + str[len] = '\0'; + buf->offset += len; +} + +/** + @brief Reads raw data from MOBIBuffer, appends it to a string and pads it with zero character + + @param[in,out] str A string to which data will be appended + @param[in] buf MOBIBuffer structure containing data + @param[in] len Length of the data to be read from buffer + */ +void mobi_buffer_appendstring(char *str, MOBIBuffer *buf, const size_t len) { + if (!str) { + buf->error = MOBI_PARAM_ERR; + return; + } + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + size_t str_len = strlen(str); + memcpy(str + str_len, buf->data + buf->offset, len); + str[str_len + len] = '\0'; + buf->offset += len; +} + +/** + @brief Reads raw data from MOBIBuffer + + @param[out] data Destination to which data will be appended + @param[in] buf MOBIBuffer structure containing data + @param[in] len Length of the data to be read from buffer + */ +void mobi_buffer_getraw(void *data, MOBIBuffer *buf, const size_t len) { + if (!data) { + buf->error = MOBI_PARAM_ERR; + return; + } + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + memcpy(data, buf->data + buf->offset, len); + buf->offset += len; +} + +/** + @brief Get pointer to MOBIBuffer data at offset + + @param[in] buf MOBIBuffer structure containing data + @param[in] len Check if requested length is available in buffer + @return Pointer to offset, or NULL on failure + */ +unsigned char * mobi_buffer_getpointer(MOBIBuffer *buf, const size_t len) { + if (buf->offset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return NULL; + } + buf->offset += len; + return buf->data + buf->offset - len; +} + +/** + @brief Read 8-bit value from MOBIBuffer into allocated memory + + Read 8-bit value from buffer into memory allocated by the function. + Returns pointer to the value, which must be freed later. + If the data is not accessible function will return null pointer. + + @param[out] val Pointer to value or null pointer on failure + @param[in] buf MOBIBuffer structure containing data + */ +void mobi_buffer_dup8(uint8_t **val, MOBIBuffer *buf) { + *val = NULL; + if (buf->offset + 1 > buf->maxlen) { + return; + } + *val = malloc(sizeof(uint8_t)); + if (*val == NULL) { + return; + } + **val = mobi_buffer_get8(buf); +} + +/** + @brief Read 16-bit value from MOBIBuffer into allocated memory + + Read 16-bit value from buffer into allocated memory. + Returns pointer to the value, which must be freed later. + If the data is not accessible function will return null pointer. + + @param[out] val Pointer to value or null pointer on failure + @param[in] buf MOBIBuffer structure containing data + */ +void mobi_buffer_dup16(uint16_t **val, MOBIBuffer *buf) { + *val = NULL; + if (buf->offset + 2 > buf->maxlen) { + return; + } + *val = malloc(sizeof(uint16_t)); + if (*val == NULL) { + return; + } + **val = mobi_buffer_get16(buf); +} + +/** + @brief Read 32-bit value from MOBIBuffer into allocated memory + + Read 32-bit value from buffer into allocated memory. + Returns pointer to the value, which must be freed later. + If the data is not accessible function will return null pointer. + + @param[out] val Pointer to value + @param[in] buf MOBIBuffer structure containing data + */ +void mobi_buffer_dup32(uint32_t **val, MOBIBuffer *buf) { + *val = NULL; + if (buf->offset + 4 > buf->maxlen) { + return; + } + *val = malloc(sizeof(uint32_t)); + if (*val == NULL) { + return; + } + **val = mobi_buffer_get32(buf); +} + +/** + @brief Copy 8-bit value from one MOBIBuffer into another + + @param[out] dest Destination buffer + @param[in] source Source buffer + */ +void mobi_buffer_copy8(MOBIBuffer *dest, MOBIBuffer *source) { + mobi_buffer_add8(dest, mobi_buffer_get8(source)); +} + +/** + @brief Copy raw value from one MOBIBuffer into another + + @param[out] dest Destination buffer + @param[in] source Source buffer + @param[in] len Number of bytes to copy + */ +void mobi_buffer_copy(MOBIBuffer *dest, MOBIBuffer *source, const size_t len) { + if (source->offset + len > source->maxlen) { + debug_print("%s", "End of buffer\n"); + source->error = MOBI_BUFFER_END; + return; + } + if (dest->offset + len > dest->maxlen) { + debug_print("%s", "End of buffer\n"); + dest->error = MOBI_BUFFER_END; + return; + } + memcpy(dest->data + dest->offset, source->data + source->offset, len); + dest->offset += len; + source->offset += len; +} + +/** + @brief Copy raw value within one MOBIBuffer + + Memmove len bytes from offset (relative to current position) + to current position in buffer and advance buffer position. + Data may overlap. + + @param[out] buf Buffer + @param[in] offset Offset to read from + @param[in] len Number of bytes to copy + */ +void mobi_buffer_move(MOBIBuffer *buf, const int offset, const size_t len) { + size_t aoffset = (size_t) abs(offset); + unsigned char *source = buf->data + buf->offset; + if (offset >= 0) { + if (buf->offset + aoffset + len > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + source += aoffset; + } else { + if ( (buf->offset < aoffset) || (buf->offset + len > buf->maxlen) ) { + debug_print("%s", "Beyond start/end of buffer\n"); + buf->error = MOBI_BUFFER_END; + return; + } + source -= aoffset; + } + memmove(buf->data + buf->offset, source, len); + buf->offset += len; +} + +/** + @brief Check if buffer data header contains magic signature + + @param[in] buf MOBIBuffer buffer containing data + @param[in] magic Magic signature + @return boolean true on match, false otherwise + */ +bool mobi_buffer_match_magic(MOBIBuffer *buf, const char *magic) { + const size_t magic_length = strlen(magic); + if (buf->offset + magic_length > buf->maxlen) { + return false; + } + if (memcmp(buf->data + buf->offset, magic, magic_length) == 0) { + return true; + } + return false; +} + +/** + @brief Check if buffer contains magic signature at given offset + + @param[in] buf MOBIBuffer buffer containing data + @param[in] magic Magic signature + @param[in] offset Offset + @return boolean true on match, false otherwise + */ +bool mobi_buffer_match_magic_offset(MOBIBuffer *buf, const char *magic, const size_t offset) { + bool match = false; + if (offset <= buf->maxlen) { + const size_t save_offset = buf->offset; + buf->offset = offset; + match = mobi_buffer_match_magic(buf, magic); + buf->offset = save_offset; + } + return match; +} + +/** + @brief Move current buffer offset by diff bytes + + @param[in,out] buf MOBIBuffer buffer containing data + @param[in] diff Number of bytes by which the offset is adjusted + */ +void mobi_buffer_seek(MOBIBuffer *buf, const int diff) { + size_t adiff = (size_t) abs(diff); + if (diff >= 0) { + if (buf->offset + adiff <= buf->maxlen) { + buf->offset += adiff; + return; + } + } else { + if (buf->offset >= adiff) { + buf->offset -= adiff; + return; + } + } + buf->error = MOBI_BUFFER_END; + debug_print("%s", "End of buffer\n"); +} + +/** + @brief Set buffer offset to pos position + + @param[in,out] buf MOBIBuffer buffer containing data + @param[in] pos New position + */ +void mobi_buffer_setpos(MOBIBuffer *buf, const size_t pos) { + if (pos <= buf->maxlen) { + buf->offset = pos; + return; + } + buf->error = MOBI_BUFFER_END; + debug_print("%s", "End of buffer\n"); +} + +/** + @brief Free pointer to MOBIBuffer structure and pointer to data + + Free data initialized with mobi_buffer_init(); + + @param[in] buf MOBIBuffer structure + */ +void mobi_buffer_free(MOBIBuffer *buf) { + if (buf == NULL) { return; } + if (buf->data != NULL) { + free(buf->data); + } + free(buf); +} + +/** + @brief Free pointer to MOBIBuffer structure + + Free data initialized with mobi_buffer_init_null(); + Unlike mobi_buffer_free() it will not free pointer to buf->data + + @param[in] buf MOBIBuffer structure + */ +void mobi_buffer_free_null(MOBIBuffer *buf) { + if (buf == NULL) { return; } + free(buf); +} diff --git a/Charcoal/Charcoal/libmobi-public/src/buffer.h b/Charcoal/Charcoal/libmobi-public/src/buffer.h new file mode 100644 index 0000000..eecff21 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/buffer.h @@ -0,0 +1,58 @@ +/** @file buffer.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_buffer_h +#define libmobi_buffer_h + +#include "config.h" +#include "mobi.h" + +/** + @brief Buffer to read to/write from + */ +typedef struct { + size_t offset; /**< Current offset in respect to buffer start */ + size_t maxlen; /**< Length of the buffer data */ + unsigned char *data; /**< Pointer to buffer data */ + MOBI_RET error; /**< MOBI_SUCCESS = 0 if operation on buffer is successful, non-zero value on failure */ +} MOBIBuffer; + +MOBIBuffer * mobi_buffer_init(const size_t len); +MOBIBuffer * mobi_buffer_init_null(unsigned char *data, const size_t len); +void mobi_buffer_resize(MOBIBuffer *buf, const size_t newlen); +void mobi_buffer_add8(MOBIBuffer *buf, const uint8_t data); +void mobi_buffer_add16(MOBIBuffer *buf, const uint16_t data); +void mobi_buffer_add32(MOBIBuffer *buf, const uint32_t data); +void mobi_buffer_addraw(MOBIBuffer *buf, const unsigned char* data, const size_t len); +void mobi_buffer_addstring(MOBIBuffer *buf, const char *str); +void mobi_buffer_addzeros(MOBIBuffer *buf, const size_t count); +uint8_t mobi_buffer_get8(MOBIBuffer *buf); +uint16_t mobi_buffer_get16(MOBIBuffer *buf); +uint32_t mobi_buffer_get32(MOBIBuffer *buf); +uint32_t mobi_buffer_get_varlen(MOBIBuffer *buf, size_t *len); +uint32_t mobi_buffer_get_varlen_dec(MOBIBuffer *buf, size_t *len); +void mobi_buffer_dup8(uint8_t **val, MOBIBuffer *buf); +void mobi_buffer_dup16(uint16_t **val, MOBIBuffer *buf); +void mobi_buffer_dup32(uint32_t **val, MOBIBuffer *buf); +void mobi_buffer_getstring(char *str, MOBIBuffer *buf, const size_t len); +void mobi_buffer_appendstring(char *str, MOBIBuffer *buf, const size_t len); +void mobi_buffer_getraw(void *data, MOBIBuffer *buf, const size_t len); +unsigned char * mobi_buffer_getpointer(MOBIBuffer *buf, const size_t len); +void mobi_buffer_copy8(MOBIBuffer *dest, MOBIBuffer *source); +void mobi_buffer_move(MOBIBuffer *buf, const int offset, const size_t len); +void mobi_buffer_copy(MOBIBuffer *dest, MOBIBuffer *source, const size_t len); +bool mobi_buffer_match_magic(MOBIBuffer *buf, const char *magic); +bool mobi_buffer_match_magic_offset(MOBIBuffer *buf, const char *magic, const size_t offset); +void mobi_buffer_seek(MOBIBuffer *buf, const int diff); +void mobi_buffer_setpos(MOBIBuffer *buf, const size_t pos); +void mobi_buffer_free(MOBIBuffer *buf); +void mobi_buffer_free_null(MOBIBuffer *buf); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/common.c b/Charcoal/Charcoal/libmobi-public/src/common.c new file mode 100644 index 0000000..409a4b4 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/common.c @@ -0,0 +1,621 @@ +/** @file common.c + * + * @brief common tools functions + * + * @example common.c + * Common functions for tools + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include "common.h" + +#ifdef _WIN32 +# include +# define mkdir(path,flags) _mkdir(path) +const char separator = '\\'; +#else +const char separator = '/'; +#endif +bool outdir_opt = false; +char outdir[FILENAME_MAX]; + +#define UNUSED(x) (void)(x) + +#ifndef min +# define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/** + @brief Messages for libmobi return codes + For reference see enum MOBI_RET in mobi.h + */ +const char *libmobi_messages[] = { + "Success", + "Generic error", + "Wrong function parameter", + "Corrupted data", + "File not found", + "Document is encrypted", + "Unsupported document format", + "Memory allocation error", + "Initialization error", + "Buffer error", + "XML error", + "Invalid DRM pid", + "DRM key not found", + "DRM support not included", + "Write failed", + "DRM expired" +}; + +#define LIBMOBI_MSG_COUNT ARRAYSIZE(libmobi_messages) + +/** + @brief Return message for given libmobi return code + @param[in] ret Libmobi return code + @return Message string + */ +const char * libmobi_msg(const MOBI_RET ret) { + size_t index = ret; + if (index < LIBMOBI_MSG_COUNT) { + return libmobi_messages[index]; + } + return "Unknown error"; +} + +/** + @brief Parse file name into file path and base name. + Dirname or basename can be skipped by setting to null. + @param[in] fullpath Full file path + @param[in,out] dirname Will be set to full dirname + @param[in,out] basename Will be set to file basename + @param[in] buf_len Size of each ouput buffer: dirname and basename + */ +void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len) { + if (buf_len == 0) { + return; + } + char *p = strrchr(fullpath, separator); + if (p) { + p += 1; + if (dirname) { + size_t dirlen = min(buf_len - 1, (size_t) (p - fullpath)); + strncpy(dirname, fullpath, dirlen); + dirname[dirlen] = '\0'; + } + if (basename) { + strncpy(basename, p, buf_len - 1); + basename[buf_len - 1] = '\0'; + } + } + else { + if (dirname) { + dirname[0] = '\0'; + } + if (basename) { + strncpy(basename, fullpath, buf_len - 1); + basename[buf_len - 1] = '\0'; + } + } + if (basename) { + p = strrchr(basename, '.'); + if (p) { + *p = '\0'; + } + } +} + +/** + @brief Make directory + @param[in] path Path + @return SUCCESS or ERROR + */ +int make_directory(const char *path) { + errno = 0; + if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST) { + int errsv = errno; + printf("Creating directory \"%s\" failed (%s)\n", path, strerror(errsv)); + return ERROR; + } + return SUCCESS; +} + +/** + @brief Create subfolder in directory + @param[in,out] newdir Path to created subfolder + @param[in] buf_len Buffer size fo created subfolder + @param[in] parent_dir Directory path + @param[in] subdir_name Subfolder name + @return SUCCESS or ERROR + */ +int create_subdir(char *newdir, const size_t buf_len, const char *parent_dir, const char *subdir_name) { + int n = snprintf(newdir, buf_len, "%s%c%s", parent_dir, separator, subdir_name); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= buf_len) { + printf("File name too long: %s\n", newdir); + return ERROR; + } + return make_directory(newdir); +} + +/** + @brief Open file descriptor and write buffer to it + @param[in] buffer Buffer + @param[in] len Buffer length + @param[in] path File path + @return SUCCESS or ERROR + */ +int write_file(const unsigned char *buffer, const size_t len, const char *path) { + errno = 0; + FILE *file = fopen(path, "wb"); + if (file == NULL) { + int errsv = errno; + printf("Could not open file for writing: %s (%s)\n", path, strerror(errsv)); + return ERROR; + } + size_t n = fwrite(buffer, 1, len, file); + if (n != len) { + int errsv = errno; + printf("Error writing to file: %s (%s)\n", path, strerror(errsv)); + fclose(file); + return ERROR; + } + fclose(file); + return SUCCESS; +} + +/** + @brief Write content to file in directory + @param[in] dir Directory path + @param[in] name File name + @param[in] buffer Buffer + @param[in] len Buffer length + @return SUCCESS or ERROR + */ +int write_to_dir(const char *dir, const char *name, const unsigned char *buffer, const size_t len) { + char path[FILENAME_MAX]; + int n = snprintf(path, sizeof(path), "%s%c%s", dir, separator, name); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(path)) { + printf("File name too long\n"); + return ERROR; + } + return write_file(buffer, len, path); +} + +/** + @brief Check whether given path exists and is a directory + @param[in] path Path to be tested + @return True if directory exists, false otherwise + */ +bool dir_exists(const char *path) { + struct stat sb; + if (stat(path, &sb) != 0) { + int errsv = errno; + printf("Path \"%s\" is not accessible (%s)\n", path, strerror(errsv)); + return false; + } + if (!S_ISDIR(sb.st_mode)) { + printf("Path \"%s\" is not a directory\n", path); + return false; + } + return true; +} + +/** + @brief Make sure we use consistent separators on Windows builds + @param[in,out] path Path to be fixed + */ +void normalize_path(char *path) { +#ifdef _WIN32 + if (path != NULL) { + for (size_t i = 0; i <= strlen(path); i++) { + if (path[i] == '/') { + path[i] = separator; + } + } + } +#else + UNUSED(path); +#endif +} + + +/** + @brief Print summary meta information + @param[in] m MOBIData structure + */ +void print_summary(const MOBIData *m) { + char *title = mobi_meta_get_title(m); + if (title) { + printf("Title: %s\n", title); + free(title); + } + char *author = mobi_meta_get_author(m); + if (author) { + printf("Author: %s\n", author); + free(author); + } + char *contributor = mobi_meta_get_contributor(m); + uint32_t major = 0, minor = 0, build = 0; + bool is_calibre = false; + if (contributor) { + const char *calibre_contributor = "calibre ("; + if (strncmp(contributor, calibre_contributor, strlen(calibre_contributor)) == 0) { + is_calibre = true; + sscanf(contributor, "calibre (%u.%u.%u)", &major, &minor, &build); + } else { + printf("Contributor: %s\n", contributor); + } + free(contributor); + } + char *subject = mobi_meta_get_subject(m); + if (subject) { + printf("Subject: %s\n", subject); + free(subject); + } + char *publisher = mobi_meta_get_publisher(m); + if (publisher) { + printf("Publisher: %s\n", publisher); + free(publisher); + } + char *date = mobi_meta_get_publishdate(m); + if (date) { + printf("Publishing date: %s\n", date); + free(date); + } + char *description = mobi_meta_get_description(m); + if (description) { + printf("Description: %s\n", description); + free(description); + } + char *review = mobi_meta_get_review(m); + if (review) { + printf("Review: %s\n", review); + free(review); + } + char *imprint = mobi_meta_get_imprint(m); + if (imprint) { + printf("Imprint: %s\n", imprint); + free(imprint); + } + char *copyright = mobi_meta_get_copyright(m); + if (copyright) { + printf("Copyright: %s\n", copyright); + free(copyright); + } + char *isbn = mobi_meta_get_isbn(m); + if (isbn) { + printf("ISBN: %s\n", isbn); + free(isbn); + } + char *asin = mobi_meta_get_asin(m); + if (asin) { + printf("ASIN: %s\n", asin); + free(asin); + } + char *language = mobi_meta_get_language(m); + if (language) { + printf("Language: %s", language); + free(language); + if (m->mh && m->mh->text_encoding) { + uint32_t encoding = *m->mh->text_encoding; + if (encoding == MOBI_CP1252) { + printf(" (cp1252)"); + } else if (encoding == MOBI_UTF8) { + printf(" (utf8)"); + } + } + printf("\n"); + } + if (mobi_is_dictionary(m)) { + printf("Dictionary"); + if (m->mh && m->mh->dict_input_lang && m->mh->dict_output_lang && + *m->mh->dict_input_lang && *m->mh->dict_output_lang) { + const char *locale_in = mobi_get_locale_string(*m->mh->dict_input_lang); + const char *locale_out = mobi_get_locale_string(*m->mh->dict_output_lang); + printf(": %s => %s", locale_in ? locale_in : "unknown", locale_out ? locale_out : "unknown"); + } + printf("\n"); + } + printf("__\n"); + if (strcmp(m->ph->type, "TEXt") == 0) { + if (strcmp(m->ph->creator, "TlDc") == 0) { + printf("TealDoc\n"); + } else { + printf("PalmDoc\n"); + } + } else { + printf("Mobi version: %zu", mobi_get_fileversion(m)); + if (mobi_is_hybrid(m)) { + size_t version = mobi_get_fileversion(m->next); + if (version != MOBI_NOTSET) { + printf(" (hybrid with version %zu)", version); + } + } + printf("\n"); + } + if (mobi_is_replica(m)) { + printf("Print Replica\n"); + } + if (mobi_is_encrypted(m)) { + printf("Document is encrypted\n"); + } + if (is_calibre) { + printf("Creator software: calibre %u.%u.%u\n", major, minor, build); + } else { + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORSOFT); + if (exth) { + printf("Creator software: "); + uint32_t creator = mobi_decode_exthvalue(exth->data, exth->size); + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORMAJOR); + if (exth) { + major = mobi_decode_exthvalue(exth->data, exth->size); + } + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORMINOR); + if (exth) { + minor = mobi_decode_exthvalue(exth->data, exth->size); + } + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORBUILD); + if (exth) { + build = mobi_decode_exthvalue(exth->data, exth->size); + } + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORBUILDREV); + if (major == 2 && minor == 9 && build == 0 && exth) { + char *rev = mobi_decode_exthstring(m, exth->data, exth->size); + if (rev) { + if (strcmp(rev, "0730-890adc2") == 0) { + is_calibre = true; + } + free(rev); + } + } + switch (creator) { + case 0: + printf("mobipocket reader %u.%u.%u", major, minor, build); + break; + case 1: + case 101: + printf("mobigen %u.%u.%u", major, minor, build); + break; + case 2: + printf("mobipocket creator %u.%u.%u", major, minor, build); + break; + case 200: + printf("kindlegen %u.%u.%u (windows)", major, minor, build); + if (is_calibre) { + printf(" or calibre"); + } + break; + case 201: + printf("kindlegen %u.%u.%u (linux)", major, minor, build); + if ((major == 1 && minor == 2 && build == 33307) || + (major == 2 && minor == 0 && build == 101) || + is_calibre) { + printf(" or calibre"); + } + break; + case 202: + printf("kindlegen %u.%u.%u (mac)", major, minor, build); + if (is_calibre) { + printf(" or calibre"); + } + break; + default: + printf("unknown"); + break; + } + printf("\n"); + } + } +} + +/** + @brief Print all loaded EXTH record tags + @param[in] m MOBIData structure + */ +void print_exth(const MOBIData *m) { + if (m->eh == NULL) { + return; + } + /* Linked list of MOBIExthHeader structures holds EXTH records */ + const MOBIExthHeader *curr = m->eh; + if (curr != NULL) { + printf("\nEXTH records:\n"); + } + uint32_t val32; + while (curr != NULL) { + /* check if it is a known tag and get some more info if it is */ + MOBIExthMeta tag = mobi_get_exthtagmeta_by_tag(curr->tag); + if (tag.tag == 0) { + /* unknown tag */ + /* try to print the record both as string and numeric value */ + char *str = malloc(curr->size + 1); + if (!str) { + printf("Memory allocation failed\n"); + exit(1); + } + unsigned i = 0; + unsigned char *p = curr->data; + while (i < curr->size && isprint(*p)) { + str[i] = (char)*p++; + i++; + } + str[i] = '\0'; + val32 = mobi_decode_exthvalue(curr->data, curr->size); + printf("Unknown (%i): %s (%u)\n", curr->tag, str, val32); + free(str); + } else { + /* known tag */ + size_t size = curr->size; + unsigned char *data = curr->data; + switch (tag.type) { + /* numeric */ + case EXTH_NUMERIC: + val32 = mobi_decode_exthvalue(data, size); + printf("%s (%i): %u\n", tag.name, tag.tag, val32); + break; + /* string */ + case EXTH_STRING: + { + char *exth_string = mobi_decode_exthstring(m, data, size); + if (exth_string) { + printf("%s (%i): %s\n", tag.name, tag.tag, exth_string); + free(exth_string); + } + break; + } + /* binary */ + case EXTH_BINARY: + { + unsigned i = 0; + const size_t str_len = 2 * size + 1; + char *str = malloc(str_len); + if (!str) { + printf("Memory allocation failed\n"); + exit(1); + } + str[0] = '\0'; + while (size) { + uint8_t val8 = *data++; + snprintf(&str[i], str_len - i, "%02x", val8); + i += 2; + size--; + } + printf("%s (%i): 0x%s\n", tag.name, tag.tag, str); + free(str); + break; + } + default: + break; + } + } + curr = curr->next; + } +} + +/** + @brief Set PID for decryption + @param[in,out] m MOBIData structure + @param[in] pid Serial number + @return SUCCESS or error code + */ +int set_decryption_pid(MOBIData *m, const char *pid) { + printf("\nVerifying PID %s...", pid); + MOBI_RET mobi_ret = mobi_drm_setkey(m, pid); + if (mobi_ret != MOBI_SUCCESS) { + printf("failed (%s)\n", libmobi_msg(mobi_ret)); + return (int) mobi_ret; + } + printf("ok\n"); + return SUCCESS; +} + +/** + @brief Set device serial number for decryption + @param[in,out] m MOBIData structure + @param[in] serial Serial number + @return SUCCESS or error code + */ +int set_decryption_serial(MOBIData *m, const char *serial) { + printf("\nVerifying serial %s... ", serial); + MOBI_RET mobi_ret = mobi_drm_setkey_serial(m, serial); + if (mobi_ret != MOBI_SUCCESS) { + printf("failed (%s)\n", libmobi_msg(mobi_ret)); + return (int) mobi_ret; + } + printf("ok\n"); + return SUCCESS; +} + +/** + @brief Set key for decryption. Use user supplied pid or device serial number + @param[in,out] m MOBIData structure + @param[in] serial Serial number + @param[in] pid Pid + @return SUCCESS or error code + */ +int set_decryption_key(MOBIData *m, const char *serial, const char *pid) { + + if (!pid && !serial) { + return SUCCESS; + } + if (!mobi_is_encrypted(m)) { + printf("\nDocument is not encrypted, ignoring PID/serial\n"); + return SUCCESS; + } + if (m->rh && m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + printf("\nEncryption type 1, ignoring PID/serial\n"); + return SUCCESS; + } + int ret = SUCCESS; + if (pid && (ret = set_decryption_pid(m, pid)) == SUCCESS) { + return SUCCESS; + } + if (serial) { + ret = set_decryption_serial(m, serial); + } + return ret; +} + +/** + @brief Save mobi file + + @param[in,out] m MOBIData struicture + @param[in] fullpath Full file path + @param[in] suffix Suffix appended to file name + @return SUCCESS or ERROR + */ +int save_mobi(MOBIData *m, const char *fullpath, const char *suffix) { + char outfile[FILENAME_MAX]; + char basename[FILENAME_MAX]; + char dirname[FILENAME_MAX]; + split_fullpath(fullpath, dirname, basename, FILENAME_MAX); + const char *ext = (mobi_get_fileversion(m) >= 8) ? "azw3" : "mobi"; + int n; + if (outdir_opt) { + n = snprintf(outfile, sizeof(outfile), "%s%s-%s.%s", outdir, basename, suffix, ext); + } else { + n = snprintf(outfile, sizeof(outfile), "%s%s-%s.%s", dirname, basename, suffix, ext); + } + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(outfile)) { + printf("File name too long\n"); + return ERROR; + } + + /* write */ + printf("Saving %s...\n", outfile); + FILE *file_out = fopen(outfile, "wb"); + if (file_out == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", outfile, strerror(errsv)); + return ERROR; + } + MOBI_RET mobi_ret = mobi_write_file(file_out, m); + fclose(file_out); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error writing file (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + return SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/common.h b/Charcoal/Charcoal/libmobi-public/src/common.h new file mode 100644 index 0000000..77115c2 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/common.h @@ -0,0 +1,78 @@ +/** @file common.h + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef common_h +#define common_h + +#include +#include + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif + +#ifdef HAVE_GETOPT +# include +#else +# include "win32/getopt.h" +#endif + +/* return codes */ +#define ERROR 1 +#define SUCCESS 0 + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#if defined(__clang__) +# define COMPILER "clang " __VERSION__ +#elif defined(__SUNPRO_C) +# define COMPILER "suncc " STR(__SUNPRO_C) +#elif defined(__GNUC__) +# if (defined(__MINGW32__) || defined(__MINGW64__)) +# define COMPILER "gcc (MinGW) " __VERSION__ +# else +# define COMPILER "gcc " __VERSION__ +# endif +#elif defined(_MSC_VER) +# define COMPILER "MSVC++ " STR(_MSC_VER) +#else +# define COMPILER "unknown" +#endif + +#if !defined S_ISDIR && defined S_IFDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISDIR +# error "At least one of S_ISDIR or S_IFDIR macros is required" +#endif + +#define FULLNAME_MAX 1024 + +extern const char separator; +extern bool outdir_opt; +extern char outdir[FILENAME_MAX]; + +const char * libmobi_msg(const MOBI_RET ret); +void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len); +int make_directory(const char *path); +int create_subdir(char *newdir, const size_t buf_len, const char *parent_dir, const char *subdir_name); +int write_file(const unsigned char *buffer, const size_t len, const char *path); +int write_to_dir(const char *dir, const char *name, const unsigned char *buffer, const size_t len); +bool dir_exists(const char *path); +void normalize_path(char *path); +void print_summary(const MOBIData *m); +void print_exth(const MOBIData *m); +int set_decryption_key(MOBIData *m, const char *serial, const char *pid); +int set_decryption_pid(MOBIData *m, const char *pid); +int set_decryption_serial(MOBIData *m, const char *serial); +int save_mobi(MOBIData *m, const char *fullpath, const char *suffix); +#endif /* common_h */ diff --git a/Charcoal/Charcoal/libmobi-public/src/common.h - Shortcut.lnk b/Charcoal/Charcoal/libmobi-public/src/common.h - Shortcut.lnk new file mode 100644 index 0000000..e7ca444 Binary files /dev/null and b/Charcoal/Charcoal/libmobi-public/src/common.h - Shortcut.lnk differ diff --git a/Charcoal/Charcoal/libmobi-public/src/compression - Copy.c b/Charcoal/Charcoal/libmobi-public/src/compression - Copy.c new file mode 100644 index 0000000..cf39232 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/compression - Copy.c @@ -0,0 +1,221 @@ +/** @file compression.c + * @brief Functions handling compression + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include "compression.h" +#include "buffer.h" +#include "mobi.h" +#include "debug.h" + + +/** + @brief Decompressor fo PalmDOC version of LZ77 compression + + Decompressor based on this algorithm: + http://en.wikibooks.org/wiki/Data_Compression/Dictionary_compression#PalmDoc + + @param[out] out Decompressed destination data + @param[in] in Compressed source data + @param[in,out] len_out Size of the memory reserved for decompressed data. + On return it is set to actual size of decompressed data + @param[in] len_in Size of compressed data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decompress_lz77(unsigned char *out, const unsigned char *in, size_t *len_out, const size_t len_in) { + MOBI_RET ret = MOBI_SUCCESS; + MOBIBuffer *buf_in = mobi_buffer_init_null((unsigned char *) in, len_in); + if (buf_in == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBIBuffer *buf_out = mobi_buffer_init_null(out, *len_out); + if (buf_out == NULL) { + mobi_buffer_free_null(buf_in); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + while (ret == MOBI_SUCCESS && buf_in->offset < buf_in->maxlen) { + uint8_t byte = mobi_buffer_get8(buf_in); + /* byte pair: space + char */ + if (byte >= 0xc0) { + mobi_buffer_add8(buf_out, ' '); + mobi_buffer_add8(buf_out, byte ^ 0x80); + } + /* length, distance pair */ + /* 0x8000 + (distance << 3) + ((length-3) & 0x07) */ + else if (byte >= 0x80) { + uint8_t next = mobi_buffer_get8(buf_in); + uint16_t distance = ((((byte << 8) | ((uint8_t)next)) >> 3) & 0x7ff); + uint8_t length = (next & 0x7) + 3; + while (length--) { + mobi_buffer_move(buf_out, -distance, 1); + } + } + /* single char, not modified */ + else if (byte >= 0x09) { + mobi_buffer_add8(buf_out, byte); + } + /* val chars not modified */ + else if (byte >= 0x01) { + mobi_buffer_copy(buf_out, buf_in, byte); + } + /* char '\0', not modified */ + else { + mobi_buffer_add8(buf_out, byte); + } + if (buf_in->error || buf_out->error) { + ret = MOBI_BUFFER_END; + } + } + *len_out = buf_out->offset; + mobi_buffer_free_null(buf_out); + mobi_buffer_free_null(buf_in); + return ret; +} + +/** + @brief Read at most 8 bytes from buffer, big-endian + + If buffer data is shorter returned value is padded with zeroes + + @param[in] buf MOBIBuffer structure to read from + @return 64-bit value + */ +static MOBI_INLINE uint64_t mobi_buffer_fill64(MOBIBuffer *buf) { + uint64_t val = 0; + uint8_t i = 8; + size_t bytesleft = buf->maxlen - buf->offset; + unsigned char *ptr = buf->data + buf->offset; + while (i-- && bytesleft--) { + val |= (uint64_t) *ptr++ << (i * 8); + } + /* increase counter by 4 bytes only, 4 bytes overlap on each call */ + buf->offset += 4; + return val; +} + +/** + @brief Internal function for huff/cdic decompression + + Decompressor and HUFF/CDIC records parsing based on: + perl EBook::Tools::Mobipocket + python mobiunpack.py, calibre + + @param[out] buf_out MOBIBuffer structure with decompressed data + @param[in] buf_in MOBIBuffer structure with compressed data + @param[in] huffcdic MOBIHuffCdic structure with parsed data from huff/cdic records + @param[in] depth Depth of current recursion level + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_decompress_huffman_internal(MOBIBuffer *buf_out, MOBIBuffer *buf_in, const MOBIHuffCdic *huffcdic, size_t depth) { + if (depth > MOBI_HUFFMAN_MAXDEPTH) { + debug_print("Too many levels of recursion: %zu\n", depth); + return MOBI_DATA_CORRUPT; + } + MOBI_RET ret = MOBI_SUCCESS; + int8_t bitcount = 32; + /* this cast should be safe: max record size is 4096 */ + int bitsleft = (int) (buf_in->maxlen * 8); + uint8_t code_length = 0; + uint64_t buffer = mobi_buffer_fill64(buf_in); + while (ret == MOBI_SUCCESS) { + if (bitcount <= 0) { + bitcount += 32; + buffer = mobi_buffer_fill64(buf_in); + } + uint32_t code = (buffer >> bitcount) & 0xffffffffU; + /* lookup code in table1 */ + uint32_t t1 = huffcdic->table1[code >> 24]; + /* get maxcode and codelen from t1 */ + code_length = t1 & 0x1f; + uint32_t maxcode = (((t1 >> 8) + 1) << (32 - code_length)) - 1; + /* check termination bit */ + if (!(t1 & 0x80)) { + /* get offset from mincode, maxcode tables */ + while (code < huffcdic->mincode_table[code_length]) { + if (++code_length >= HUFF_CODETABLE_SIZE) { + debug_print("Wrong offset to mincode table: %hhu\n", code_length); + return MOBI_DATA_CORRUPT; + } + } + maxcode = huffcdic->maxcode_table[code_length]; + } + bitcount -= code_length; + bitsleft -= code_length; + if (bitsleft < 0) { + break; + } + /* get index for symbol offset */ + uint32_t index = (uint32_t) (maxcode - code) >> (32 - code_length); + /* check which part of cdic to use */ + uint16_t cdic_index = (uint16_t) ((uint32_t)index >> huffcdic->code_length); + if (index >= huffcdic->index_count) { + debug_print("Wrong symbol offsets index: %u\n", index); + return MOBI_DATA_CORRUPT; + } + /* get offset */ + uint32_t offset = huffcdic->symbol_offsets[index]; + uint32_t symbol_length = (uint32_t) huffcdic->symbols[cdic_index][offset] << 8 | (uint32_t) huffcdic->symbols[cdic_index][offset + 1]; + /* 1st bit is is_decompressed flag */ + int is_decompressed = symbol_length >> 15; + /* get rid of flag */ + symbol_length &= 0x7fff; + if (is_decompressed) { + /* symbol is at (offset + 2), 2 bytes used earlier for symbol length */ + mobi_buffer_addraw(buf_out, (huffcdic->symbols[cdic_index] + offset + 2), symbol_length); + ret = buf_out->error; + } else { + /* symbol is compressed */ + /* TODO cache uncompressed symbols? */ + MOBIBuffer buf_sym; + buf_sym.data = huffcdic->symbols[cdic_index] + offset + 2; + buf_sym.offset = 0; + buf_sym.maxlen = symbol_length; + buf_sym.error = MOBI_SUCCESS; + ret = mobi_decompress_huffman_internal(buf_out, &buf_sym, huffcdic, depth + 1); + } + } + return ret; +} + +/** + @brief Decompressor for huff/cdic compressed text records + + Decompressor and HUFF/CDIC records parsing based on: + perl EBook::Tools::Mobipocket + python mobiunpack.py, calibre + + @param[out] out Decompressed destination data + @param[in] in Compressed source data + @param[in,out] len_out Size of the memory reserved for decompressed data. + On return it is set to actual size of decompressed data + @param[in] len_in Size of compressed data + @param[in] huffcdic MOBIHuffCdic structure with parsed data from huff/cdic records + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decompress_huffman(unsigned char *out, const unsigned char *in, size_t *len_out, size_t len_in, const MOBIHuffCdic *huffcdic) { + MOBIBuffer *buf_in = mobi_buffer_init_null((unsigned char *) in, len_in); + if (buf_in == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBIBuffer *buf_out = mobi_buffer_init_null(out, *len_out); + if (buf_out == NULL) { + mobi_buffer_free_null(buf_in); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = mobi_decompress_huffman_internal(buf_out, buf_in, huffcdic, 0); + *len_out = buf_out->offset; + mobi_buffer_free_null(buf_out); + mobi_buffer_free_null(buf_in); + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/compression.c b/Charcoal/Charcoal/libmobi-public/src/compression.c new file mode 100644 index 0000000..cf39232 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/compression.c @@ -0,0 +1,221 @@ +/** @file compression.c + * @brief Functions handling compression + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include "compression.h" +#include "buffer.h" +#include "mobi.h" +#include "debug.h" + + +/** + @brief Decompressor fo PalmDOC version of LZ77 compression + + Decompressor based on this algorithm: + http://en.wikibooks.org/wiki/Data_Compression/Dictionary_compression#PalmDoc + + @param[out] out Decompressed destination data + @param[in] in Compressed source data + @param[in,out] len_out Size of the memory reserved for decompressed data. + On return it is set to actual size of decompressed data + @param[in] len_in Size of compressed data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decompress_lz77(unsigned char *out, const unsigned char *in, size_t *len_out, const size_t len_in) { + MOBI_RET ret = MOBI_SUCCESS; + MOBIBuffer *buf_in = mobi_buffer_init_null((unsigned char *) in, len_in); + if (buf_in == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBIBuffer *buf_out = mobi_buffer_init_null(out, *len_out); + if (buf_out == NULL) { + mobi_buffer_free_null(buf_in); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + while (ret == MOBI_SUCCESS && buf_in->offset < buf_in->maxlen) { + uint8_t byte = mobi_buffer_get8(buf_in); + /* byte pair: space + char */ + if (byte >= 0xc0) { + mobi_buffer_add8(buf_out, ' '); + mobi_buffer_add8(buf_out, byte ^ 0x80); + } + /* length, distance pair */ + /* 0x8000 + (distance << 3) + ((length-3) & 0x07) */ + else if (byte >= 0x80) { + uint8_t next = mobi_buffer_get8(buf_in); + uint16_t distance = ((((byte << 8) | ((uint8_t)next)) >> 3) & 0x7ff); + uint8_t length = (next & 0x7) + 3; + while (length--) { + mobi_buffer_move(buf_out, -distance, 1); + } + } + /* single char, not modified */ + else if (byte >= 0x09) { + mobi_buffer_add8(buf_out, byte); + } + /* val chars not modified */ + else if (byte >= 0x01) { + mobi_buffer_copy(buf_out, buf_in, byte); + } + /* char '\0', not modified */ + else { + mobi_buffer_add8(buf_out, byte); + } + if (buf_in->error || buf_out->error) { + ret = MOBI_BUFFER_END; + } + } + *len_out = buf_out->offset; + mobi_buffer_free_null(buf_out); + mobi_buffer_free_null(buf_in); + return ret; +} + +/** + @brief Read at most 8 bytes from buffer, big-endian + + If buffer data is shorter returned value is padded with zeroes + + @param[in] buf MOBIBuffer structure to read from + @return 64-bit value + */ +static MOBI_INLINE uint64_t mobi_buffer_fill64(MOBIBuffer *buf) { + uint64_t val = 0; + uint8_t i = 8; + size_t bytesleft = buf->maxlen - buf->offset; + unsigned char *ptr = buf->data + buf->offset; + while (i-- && bytesleft--) { + val |= (uint64_t) *ptr++ << (i * 8); + } + /* increase counter by 4 bytes only, 4 bytes overlap on each call */ + buf->offset += 4; + return val; +} + +/** + @brief Internal function for huff/cdic decompression + + Decompressor and HUFF/CDIC records parsing based on: + perl EBook::Tools::Mobipocket + python mobiunpack.py, calibre + + @param[out] buf_out MOBIBuffer structure with decompressed data + @param[in] buf_in MOBIBuffer structure with compressed data + @param[in] huffcdic MOBIHuffCdic structure with parsed data from huff/cdic records + @param[in] depth Depth of current recursion level + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_decompress_huffman_internal(MOBIBuffer *buf_out, MOBIBuffer *buf_in, const MOBIHuffCdic *huffcdic, size_t depth) { + if (depth > MOBI_HUFFMAN_MAXDEPTH) { + debug_print("Too many levels of recursion: %zu\n", depth); + return MOBI_DATA_CORRUPT; + } + MOBI_RET ret = MOBI_SUCCESS; + int8_t bitcount = 32; + /* this cast should be safe: max record size is 4096 */ + int bitsleft = (int) (buf_in->maxlen * 8); + uint8_t code_length = 0; + uint64_t buffer = mobi_buffer_fill64(buf_in); + while (ret == MOBI_SUCCESS) { + if (bitcount <= 0) { + bitcount += 32; + buffer = mobi_buffer_fill64(buf_in); + } + uint32_t code = (buffer >> bitcount) & 0xffffffffU; + /* lookup code in table1 */ + uint32_t t1 = huffcdic->table1[code >> 24]; + /* get maxcode and codelen from t1 */ + code_length = t1 & 0x1f; + uint32_t maxcode = (((t1 >> 8) + 1) << (32 - code_length)) - 1; + /* check termination bit */ + if (!(t1 & 0x80)) { + /* get offset from mincode, maxcode tables */ + while (code < huffcdic->mincode_table[code_length]) { + if (++code_length >= HUFF_CODETABLE_SIZE) { + debug_print("Wrong offset to mincode table: %hhu\n", code_length); + return MOBI_DATA_CORRUPT; + } + } + maxcode = huffcdic->maxcode_table[code_length]; + } + bitcount -= code_length; + bitsleft -= code_length; + if (bitsleft < 0) { + break; + } + /* get index for symbol offset */ + uint32_t index = (uint32_t) (maxcode - code) >> (32 - code_length); + /* check which part of cdic to use */ + uint16_t cdic_index = (uint16_t) ((uint32_t)index >> huffcdic->code_length); + if (index >= huffcdic->index_count) { + debug_print("Wrong symbol offsets index: %u\n", index); + return MOBI_DATA_CORRUPT; + } + /* get offset */ + uint32_t offset = huffcdic->symbol_offsets[index]; + uint32_t symbol_length = (uint32_t) huffcdic->symbols[cdic_index][offset] << 8 | (uint32_t) huffcdic->symbols[cdic_index][offset + 1]; + /* 1st bit is is_decompressed flag */ + int is_decompressed = symbol_length >> 15; + /* get rid of flag */ + symbol_length &= 0x7fff; + if (is_decompressed) { + /* symbol is at (offset + 2), 2 bytes used earlier for symbol length */ + mobi_buffer_addraw(buf_out, (huffcdic->symbols[cdic_index] + offset + 2), symbol_length); + ret = buf_out->error; + } else { + /* symbol is compressed */ + /* TODO cache uncompressed symbols? */ + MOBIBuffer buf_sym; + buf_sym.data = huffcdic->symbols[cdic_index] + offset + 2; + buf_sym.offset = 0; + buf_sym.maxlen = symbol_length; + buf_sym.error = MOBI_SUCCESS; + ret = mobi_decompress_huffman_internal(buf_out, &buf_sym, huffcdic, depth + 1); + } + } + return ret; +} + +/** + @brief Decompressor for huff/cdic compressed text records + + Decompressor and HUFF/CDIC records parsing based on: + perl EBook::Tools::Mobipocket + python mobiunpack.py, calibre + + @param[out] out Decompressed destination data + @param[in] in Compressed source data + @param[in,out] len_out Size of the memory reserved for decompressed data. + On return it is set to actual size of decompressed data + @param[in] len_in Size of compressed data + @param[in] huffcdic MOBIHuffCdic structure with parsed data from huff/cdic records + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decompress_huffman(unsigned char *out, const unsigned char *in, size_t *len_out, size_t len_in, const MOBIHuffCdic *huffcdic) { + MOBIBuffer *buf_in = mobi_buffer_init_null((unsigned char *) in, len_in); + if (buf_in == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBIBuffer *buf_out = mobi_buffer_init_null(out, *len_out); + if (buf_out == NULL) { + mobi_buffer_free_null(buf_in); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = mobi_decompress_huffman_internal(buf_out, buf_in, huffcdic, 0); + *len_out = buf_out->offset; + mobi_buffer_free_null(buf_out); + mobi_buffer_free_null(buf_in); + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/compression.h b/Charcoal/Charcoal/libmobi-public/src/compression.h new file mode 100644 index 0000000..59e116e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/compression.h @@ -0,0 +1,43 @@ +/** @file compression.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_compression_h +#define libmobi_compression_h + +#include "config.h" +#include "mobi.h" + +#ifndef MOBI_INLINE +#define MOBI_INLINE /**< Syntax for compiler inline keyword from config.h */ +#endif + +/* FIXME: what is the reasonable value? */ +#define MOBI_HUFFMAN_MAXDEPTH 20 /**< Maximal recursion level for huffman decompression routine */ +#define HUFF_CODETABLE_SIZE 33 /**< Size of min- and maxcode tables */ + + +/** + @brief Parsed data from HUFF and CDIC records needed to unpack huffman compressed text + */ +typedef struct { + size_t index_count; /**< Total number of indices in all CDIC records, stored in each CDIC record header */ + size_t index_read; /**< Number of indices parsed, used by parser */ + size_t code_length; /**< Code length value stored in CDIC record header */ + uint32_t table1[256]; /**< Table of big-endian indices from HUFF record data1 */ + uint32_t mincode_table[HUFF_CODETABLE_SIZE]; /**< Table of big-endian mincodes from HUFF record data2 */ + uint32_t maxcode_table[HUFF_CODETABLE_SIZE]; /**< Table of big-endian maxcodes from HUFF record data2 */ + uint16_t *symbol_offsets; /**< Index of symbol offsets parsed from CDIC records (index_count entries) */ + unsigned char **symbols; /**< Array of pointers to start of symbols data in each CDIC record (index = number of CDIC record) */ +} MOBIHuffCdic; + +MOBI_RET mobi_decompress_lz77(unsigned char *out, const unsigned char *in, size_t *len_out, const size_t len_in); +MOBI_RET mobi_decompress_huffman(unsigned char *out, const unsigned char *in, size_t *len_out, size_t len_in, const MOBIHuffCdic *huffcdic); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/config.h b/Charcoal/Charcoal/libmobi-public/src/config.h new file mode 100644 index 0000000..352fd4e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/config.h @@ -0,0 +1,18 @@ +/** @file src/config.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_config_h +#define mobi_config_h + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/debug.c b/Charcoal/Charcoal/libmobi-public/src/debug.c new file mode 100644 index 0000000..c364726 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/debug.c @@ -0,0 +1,159 @@ +/** @file debug.c + * @brief Debugging functions, enable by running configure --enable-debug + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include + +#include "debug.h" +#include "index.h" + +/** + @brief Debugging wrapper for free(void *ptr) + + @param[in] ptr Pointer + @param[in] file Calling file + @param[in] line Calling line + */ +void debug_free(void *ptr, const char *file, const int line) { + printf("%s:%d: free(%p)\n",file, line, ptr); + (free)(ptr); +} + +/** + @brief Debugging wrapper for malloc(size_t size) + + @param[in] size Size of memory + @param[in] file Calling file + @param[in] line Calling line + @return A pointer to the allocated memory block on success, NULL on failure + + */ +void *debug_malloc(const size_t size, const char *file, const int line) { + void *ptr = (malloc)(size); + printf("%s:%d: malloc(%d)=%p\n", file, line, (int)size, ptr); + return ptr; +} + +/** + @brief Debugging wrapper for realloc(void* ptr, size_t size) + + @param[in] ptr Pointer + @param[in] size Size of memory + @param[in] file Calling file + @param[in] line Calling line + @return A pointer to the reallocated memory block on success, NULL on failure + */ +void *debug_realloc(void *ptr, const size_t size, const char *file, const int line) { + printf("%s:%d: realloc(%p", file, line, ptr); + void *rptr = (realloc)(ptr, size); + printf(", %d)=%p\n", (int)size, rptr); + return rptr; +} + +/** + @brief Debugging wrapper for calloc(size_t num, size_t size) + + @param[in] num Number of elements to allocate + @param[in] size Size of each element + @param[in] file Calling file + @param[in] line Calling line + @return A pointer to the allocated memory block on success, NULL on failure + */ +void *debug_calloc(const size_t num, const size_t size, const char *file, const int line) { + void *ptr = (calloc)(num, size); + printf("%s:%d: calloc(%d, %d)=%p\n", file, line, (int)num, (int)size, ptr); + return ptr; +} + +/** + @brief Dump index values + + @param[in] indx Parsed index +*/ +void print_indx(const MOBIIndx *indx) { + if (indx == NULL) { return; } + for (size_t i = 0; i < indx->entries_count; i++) { + MOBIIndexEntry e = indx->entries[i]; + printf("entry[%zu]: \"%s\"\n", i, e.label); + for (size_t j = 0; j < e.tags_count; j++) { + MOBIIndexTag t = e.tags[j]; + printf(" tag[%zu] ", t.tagid); + for (size_t k = 0; k < t.tagvalues_count; k++) { + printf("[%u] ", t.tagvalues[k]); + } + printf("\n"); + } + } +} + +/** + @brief Dump inflections index (old version) + + @param[in] indx Parsed index +*/ +void print_indx_infl_old(const MOBIIndx *indx) { + if (indx == NULL) { return; } + for (size_t i = 0; i < indx->entries_count; i++) { + MOBIIndexEntry e = indx->entries[i]; + printf("entry[%zu]: \"%s\"\n", i, e.label); + for (size_t j = 0; j < e.tags_count; j++) { + MOBIIndexTag t = e.tags[j]; + printf(" tag[%zu] ", t.tagid); + if (t.tagid == 7) { + for (size_t k = 0; k < t.tagvalues_count; k += 2) { + uint32_t len = t.tagvalues[k]; + uint32_t offset = t.tagvalues[k + 1]; + char *string = mobi_get_cncx_string_flat(indx->cncx_record, offset, len); + if (string) { + printf("\"%s\" [%u] [%u]", string, len, offset); + free(string); + } + } + } else { + for (size_t k = 0; k < t.tagvalues_count; k++) { + printf("[%u] ", t.tagvalues[k]); + } + } + printf("\n"); + } + } +} + +/** + @brief Dump orthographic index (old version) + + @param[in] indx Parsed index +*/ +void print_indx_orth_old(const MOBIIndx *indx) { + if (indx == NULL) { return; } + for (size_t i = 0; i < indx->entries_count; i++) { + MOBIIndexEntry e = indx->entries[i]; + printf("entry[%zu]: \"%s\"\n", i, e.label); + for (size_t j = 0; j < e.tags_count; j++) { + MOBIIndexTag t = e.tags[j]; + printf(" tag[%zu] ", t.tagid); + if (t.tagid >= 69) { + for (size_t k = 0; k < t.tagvalues_count; k++) { + uint32_t offset = t.tagvalues[k]; + char *string = mobi_get_cncx_string(indx->cncx_record, offset); + if (string) { + printf("\"%s\" [%u] ", string, t.tagvalues[k]); + free(string); + } + } + } else { + for (size_t k = 0; k < t.tagvalues_count; k++) { + printf("[%u] ", t.tagvalues[k]); + } + } + printf("\n"); + } + } +} diff --git a/Charcoal/Charcoal/libmobi-public/src/debug.h b/Charcoal/Charcoal/libmobi-public/src/debug.h new file mode 100644 index 0000000..75507d9 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/debug.h @@ -0,0 +1,57 @@ +/** @file debug.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_debug_h +#define libmobi_debug_h + +#include "config.h" +#include "mobi.h" + +#ifndef MOBI_DEBUG +#define MOBI_DEBUG 0 /**< Turn on debugging, set this on by running "configure --enable-debug" */ +#endif + +#if MOBI_DEBUG_ALLOC +/** + @defgroup mobi_debug Debug wrappers for memory allocation functions + + Set this on by running "configure --enable-debug-alloc" + @{ + */ +#define free(x) debug_free(x, __FILE__, __LINE__) +#define malloc(x) debug_malloc(x, __FILE__, __LINE__) +#define realloc(x, y) debug_realloc(x, y, __FILE__, __LINE__) +#define calloc(x, y) debug_calloc(x, y, __FILE__, __LINE__) +/** @} */ +#endif + +void debug_free(void *ptr, const char *file, const int line); +void *debug_malloc(const size_t size, const char *file, const int line); +void *debug_realloc(void *ptr, const size_t size, const char *file, const int line); +void *debug_calloc(const size_t num, const size_t size, const char *file, const int line); +void print_indx(const MOBIIndx *indx); +void print_indx_infl_old(const MOBIIndx *indx); +void print_indx_orth_old(const MOBIIndx *indx); + +/** + @brief Macro for printing debug info to stderr. Wrapper for fprintf + @param[in] fmt Format + @param[in] ... Additional arguments + */ +#if (MOBI_DEBUG) +#define debug_print(fmt, ...) { \ + fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \ + __LINE__, __func__, __VA_ARGS__); \ +} +#else +#define debug_print(fmt, ...) +#endif + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/encryption.c b/Charcoal/Charcoal/libmobi-public/src/encryption.c new file mode 100644 index 0000000..353dba2 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/encryption.c @@ -0,0 +1,1515 @@ +/** @file encryption.c + * @brief Functions to handle encryption + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +/* PC1 routines adapted from: + + * File PC1DEC.c + * written in Borland Turbo C 2.0 on PC + * PC1 Cipher Algorithm ( Pukall Cipher 1 ) + * By Alexander PUKALL 1991 + * free code no restriction to use + * please include the name of the Author in the final software + + * Mobi encryption algorithm learned from: + + * mobidedrm.py + * Copyright (c) 2008 The Dark Reverser + */ + +#include +#include +#include +#include "util.h" +#include "debug.h" +#include "randombytes.h" +#include "sha1.h" +#include "encryption.h" + +#define INTERNAL_READER_KEY ((unsigned char*) "\x72\x38\x33\xb0\xb4\xf2\xe3\xca\xdf\x09\x01\xd6\xe2\xe0\x3f\x96") +#define INTERNAL_PUBLISHER_KEY ((unsigned char*) "\x95\xda\x7b\xed\x90\x5e\x10\x2e\x44\x4c\xb5\xe5\xc0\x25\xdf\x2c") +#define INTERNAL_READER_KEY_V1 ((unsigned char*) "QDCVEPMU675RUBSZ") +#define PIDSIZE 10 +#define SERIALSIZE 16 +#define SERIALLONGSIZE 40 +#define KEYSIZE 16 +#define COOKIESIZE 32 +#define VOUCHERSIZE 48 +#define VOUCHERS_COUNT_MAX 1024 +#define VOUCHERS_SIZE_MIN 288 +#define pk1_swap(a, b) { uint16_t tmp = a; (a) = b; (b) = tmp; } + +/** + @brief Structure for PK1 routines + */ +typedef struct { + uint16_t si, x1a2, x1a0[8]; +} MOBIPk1; + + +/** + @brief Structure for parsed drm record in record 0 header + */ +typedef struct { + uint32_t verification; /**< Verification checksum */ + uint32_t size; /**< Voucher size */ + uint32_t type; /**< Voucher type */ + uint8_t checksum; /**< Temporary key checksum */ + unsigned char *cookie; /**< Encrypted part contains key, verificationś, expiration dates, flags */ +} MOBIVoucher; + +/** + @brief Drm components extracted from EXTH records + */ +typedef struct { + unsigned char *data; /**< EXTH_TAMPERKEYS record data */ + unsigned char *token; /**< Drm token */ + size_t data_size; /**< Data size */ + size_t token_size; /**< Token size */ +} MOBIExthDrm; + +/** + @brief Helper function for PK1 encryption/decryption + + @param[in,out] pk1 PK1 structure + @param[in] i Iteration number + @return PK1 inter + */ +static uint16_t mobi_pk1_code(MOBIPk1 *pk1, const uint8_t i) { + uint16_t dx = pk1->x1a2 + i; + uint16_t ax = pk1->x1a0[i]; + uint16_t cx = 0x015a; + uint16_t bx = 0x4e35; + pk1_swap(ax, pk1->si); + pk1_swap(ax, dx); + if (ax) { ax *= bx; } + pk1_swap(ax, cx); + if (ax) { + ax *= pk1->si; + cx += ax; + } + pk1_swap(ax, pk1->si); + ax *= bx; + dx += cx; + ax += 1; + pk1->x1a2 = dx; + pk1->x1a0[i] = ax; + return ax ^ dx; +} + +/** + @brief Helper function for PK1 encryption/decryption + + @param[in,out] pk1 PK1 structure + @param[in] key 128-bit key + @return PK1 inter + */ +static uint16_t mobi_pk1_assemble(MOBIPk1 *pk1, const unsigned char key[KEYSIZE]) { + pk1->x1a0[0] = (key[0] * 256) + key[1]; + uint16_t inter = mobi_pk1_code(pk1, 0); + for (uint8_t i = 1; i < (KEYSIZE / 2); i++) { + pk1->x1a0[i] = pk1->x1a0[i - 1] ^ ((key[i * 2] * 256) + key[i * 2 + 1]); + inter ^= mobi_pk1_code(pk1, i); + } + return inter; +} + +/** + @brief Decrypt buffer with PK1 algorithm + + @param[in,out] out Decrypted buffer + @param[in] in Encrypted buffer + @param[in] length Buffer length + @param[in] key Key + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_pk1_decrypt(unsigned char *out, const unsigned char *in, size_t length, const unsigned char key[KEYSIZE]) { + if (!out || !in) { + return MOBI_INIT_FAILED; + } + unsigned char key_copy[KEYSIZE]; + memcpy(key_copy, key, KEYSIZE); + MOBIPk1 *pk1 = calloc(1, sizeof(MOBIPk1)); + while (length--) { + uint16_t inter = mobi_pk1_assemble(pk1, key_copy); + uint8_t cfc = inter >> 8; + uint8_t cfd = inter & 0xff; + uint8_t c = *in++; + c ^= (cfc ^ cfd); + for (size_t i = 0; i < KEYSIZE; i++) { + key_copy[i] ^= c; + } + *out++ = c; + } + free(pk1); + return MOBI_SUCCESS; +} + +/** + @brief Encrypt buffer with PK1 algorithm + + @param[in,out] out Decrypted buffer + @param[in] in Encrypted buffer + @param[in] length Buffer length + @param[in] key Key + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_pk1_encrypt(unsigned char *out, const unsigned char *in, size_t length, const unsigned char key[KEYSIZE]) { + if (!out || !in) { + return MOBI_INIT_FAILED; + } + MOBIPk1 *pk1 = calloc(1, sizeof(MOBIPk1)); + unsigned char key_copy[KEYSIZE]; + memcpy(key_copy, key, KEYSIZE); + while (length--) { + uint16_t inter = mobi_pk1_assemble(pk1, key_copy); + uint8_t cfc = inter >> 8; + uint8_t cfd = inter & 0xff; + uint8_t c = *in++; + for (size_t i = 0; i < KEYSIZE; i++) { + key_copy[i] ^= c; + } + c ^= (cfc ^ cfd); + *out++ = c; + } + free(pk1); + return MOBI_SUCCESS; +} + + +/** + @brief Initialize DRM structure + + @return Number of parsed records + */ +static MOBIDrm * mobi_drm_init(void) { + + MOBIDrm *drm = calloc(1, sizeof(MOBIDrm)); + if (drm == NULL) { + debug_print("%s", "Memory allocation for drm structure failed\n"); + } + return drm; +} + +/** + @brief Free DRM cookie structure + + @param[in,out] cookie Cookie + */ +static void mobi_free_cookie(MOBICookie *cookie) { + if (cookie) { + if (cookie->pid) { + free(cookie->pid); + cookie->pid = NULL; + } + free(cookie); + } +} + +/** + @brief Free DRM structure + + @param[in,out] m MOBIData structure with raw data and metadata + */ +void mobi_free_drm(MOBIData *m) { + if (m->internals) { + MOBIDrm *drm = m->internals; + if (drm->key) { + free(drm->key); + } + drm->key = NULL; + if (drm->cookies) { + while (drm->cookies_count--) { + mobi_free_cookie(drm->cookies[drm->cookies_count]); + } + free(drm->cookies); + } + drm->cookies = NULL; + free(m->internals); + m->internals = NULL; + } + +} + +/** + @brief Initialize DRM data with given key + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] key Key + @return Number of parsed records + */ +static MOBI_RET mobi_drmkey_init(MOBIData *m, const unsigned char key[KEYSIZE]) { + if (m->internals == NULL && (m->internals = mobi_drm_init()) == NULL) { + return MOBI_MALLOC_FAILED; + } + MOBIDrm *drm = m->internals; + if (drm->key == NULL) { + drm->key = malloc(KEYSIZE); + if (drm->key == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + memcpy(drm->key, key, KEYSIZE); + // remove in future versions, kept for backwards compatibility + m->drm_key = drm->key; + + debug_print("m->drm->key: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + drm->key[0], drm->key[1], drm->key[2], drm->key[3], + drm->key[4], drm->key[5], drm->key[6], drm->key[7], + drm->key[8], drm->key[9], drm->key[10], drm->key[11], + drm->key[12], drm->key[13], drm->key[14], drm->key[15]); + + return MOBI_SUCCESS; +} + +/** + @brief Read drm records from Record0 header + + @param[in,out] drm MOBIDrm structure will hold parsed data + @param[in] m MOBIData structure with raw data and metadata + @return Number of parsed records + */ +static size_t mobi_vouchers_get(MOBIVoucher **drm, const MOBIData *m) { + if (!m || !m->mh) { + return 0; + } + uint32_t offset = *m->mh->drm_offset; + uint32_t count = *m->mh->drm_count; + uint32_t size = *m->mh->drm_size; + if (offset == MOBI_NOTSET || count == 0) { + return 0; + } + /* First record */ + MOBIPdbRecord *rec = m->rec; + MOBIBuffer *buf = mobi_buffer_init_null(rec->data, rec->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return 0; + } + if (offset + size > rec->size) { + mobi_buffer_free_null(buf); + return 0; + } + mobi_buffer_setpos(buf, offset); + debug_print("%s\n", "Parsing DRM data from record 0"); + for (size_t i = 0; i < count; i++) { + drm[i] = calloc(1, sizeof(MOBIVoucher)); + if (drm[i] == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_buffer_free_null(buf); + for (size_t j = 0; j < i; j++) { + free(drm[j]); + } + return 0; + } + drm[i]->verification = mobi_buffer_get32(buf); + drm[i]->size = mobi_buffer_get32(buf); + drm[i]->type = mobi_buffer_get32(buf); + drm[i]->checksum = mobi_buffer_get8(buf); + mobi_buffer_seek(buf, 3); + drm[i]->cookie = mobi_buffer_getpointer(buf, COOKIESIZE); + debug_print("drm[%zu] verification = %#x, size = %#x, type = %#x, checksum = %#x\n", + i, drm[i]->verification, drm[i]->size, drm[i]->type, drm[i]->checksum); + if (buf->error != MOBI_SUCCESS) { + debug_print("%s\n", "DRM data too short"); + mobi_buffer_free_null(buf); + for (size_t j = 0; j < i + 1; j++) { + free(drm[j]); + } + return 0; + } + } + mobi_buffer_free_null(buf); + return count; +} + +/** + @brief Calculate checksum for key + + @param[in] key Key + @return Checksum + */ +static uint8_t mobi_drmkey_checksum(const unsigned char key[KEYSIZE]) { + size_t sum = 0; + for (size_t i = 0; i < KEYSIZE; i++) { + sum += key[i]; + } + return (uint8_t) sum; +} + +/** + @brief Free MOBIDrm structure + + @param[in] drm MOBIDrm structure + */ +static void mobi_free_vouchers(MOBIVoucher **drm, const size_t count) { + for (size_t i = 0; i < count; i++) { + free(drm[i]); + } + free(drm); +} + +/** + @brief Check whether drm expired + + @param[in] from Cookie valid after (unix timestamp in minutes) + @param[in] to Cookie valid before (unix timestamp in minutes) + @return True if drm validation dates are present and expired, false otherwise + */ +static bool mobi_drm_is_expired(const uint32_t from, const uint32_t to) { + if (from == 0 || to == MOBI_NOTSET) { + /* expiration dates not set */ + return false; + } +#if (MOBI_DEBUG) + time_t debug_from = (time_t) from * 60; + time_t debug_to = (time_t) to * 60; + debug_print("Drm validity period from %s", ctime(&debug_from)); + debug_print(" to %s", ctime(&debug_to)); +#endif + size_t current_minutes = (size_t) time(NULL) / 60; + if (current_minutes >= UINT32_MAX) { + debug_print("Drm cannot be checked, current time outside valid range: %zu\n", current_minutes); + return false; + } + if (current_minutes < from || current_minutes > to) { + debug_print("%s\n", "Drm expired"); + return true; + } + return false; +} + +/** + @brief Verify decrypted cookie + + @param[in] drm_verification Checksum from drm header + @param[in] cookie Decrypted cookie + @param[in] key_type Key type + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_cookie_verify(const uint32_t drm_verification, const unsigned char cookie[COOKIESIZE], const uint8_t key_type) { + uint32_t verification = mobi_get32be(&cookie[0]); + uint32_t flags = mobi_get32be(&cookie[4]); + debug_print("%s\n", "Parsing decrypted data from record 0"); + debug_print("verification = %#x, flags = %#x\n", verification, flags); + if (verification == drm_verification && (flags & 0x1f) == key_type) { + uint32_t to = mobi_get32be(&cookie[24]); + uint32_t from = mobi_get32be(&cookie[28]); + debug_print("from = %#x, to = %#x\n", from, to); + if (mobi_drm_is_expired(from, to)) { + return MOBI_DRM_EXPIRED; + } + return MOBI_SUCCESS; + } + return MOBI_DRM_KEYNOTFOUND; +} + +/** + @brief Get key corresponding to encryption type 2 + + If PID is supplied main key is decrypted using PID key, otherwise internal reader key is used + + @param[in,out] key Key + @param[in] pid PID, NULL if not set + @param[in] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmkey_get_v2(unsigned char key[KEYSIZE], const unsigned char *pid, const MOBIData *m) { + + MOBI_RET ret; + unsigned char *device_key = NULL; + unsigned char pidkey[KEYSIZE] = "\0"; + if (pid) { + memcpy(pidkey, pid, PIDSIZE - 2); + + ret = mobi_pk1_encrypt(pidkey, pidkey, KEYSIZE, INTERNAL_READER_KEY); + if (ret != MOBI_SUCCESS) { + return ret; + } + device_key = pidkey; + } + + MOBIVoucher **drm = malloc(*m->mh->drm_count * sizeof(MOBIVoucher*)); + if (drm == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + size_t drm_count = mobi_vouchers_get(drm, m); + bool key_expired = false; + for (size_t i = 0; i < drm_count; i++) { + /* Try 1 uses pid key, try 2 - default key */ + size_t tries = 2; + while (tries) { + const unsigned char *try_key = (tries == 2) ? device_key : INTERNAL_READER_KEY; + const uint8_t try_type = (tries == 2) ? 1 : 3; + + if (try_key && drm[i]->checksum == mobi_drmkey_checksum(try_key)) { + + unsigned char cookie[COOKIESIZE]; + ret = mobi_pk1_decrypt(cookie, drm[i]->cookie, COOKIESIZE, try_key); + if (ret != MOBI_SUCCESS) { + // fatal error + mobi_free_vouchers(drm, drm_count); + return ret; + } + + ret = mobi_cookie_verify(drm[i]->verification, cookie, try_type); + if (ret == MOBI_SUCCESS) { + memcpy(key, &cookie[8], KEYSIZE); + mobi_free_vouchers(drm, drm_count); + if (tries == 2) { + debug_print("Cookie encrypted with pid key%s", "\n"); + } else { + debug_print("Cookie encrypted with default key%s", "\n"); + } + return MOBI_SUCCESS; + } + if (ret == MOBI_DRM_EXPIRED) { + key_expired = true; + } + } + tries--; + } + } + mobi_free_vouchers(drm, drm_count); + return key_expired ? MOBI_DRM_EXPIRED : MOBI_DRM_KEYNOTFOUND; +} + +/** + @brief Get key corresponding for encryption type 1 + + Main key is encrypted with internal reader key (old version) + + @param[in,out] key Key + @param[in] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmkey_get_v1(unsigned char key[KEYSIZE], const MOBIData *m) { + if (m == NULL || m->ph == NULL) { + return MOBI_DATA_CORRUPT; + } + /* First record */ + MOBIPdbRecord *rec = m->rec; + MOBIBuffer *buf = mobi_buffer_init_null(rec->data, rec->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + size_t mobi_version = mobi_get_fileversion(m); + + if (mobi_version > 1) { + /* offset mobi header + record 0 header (+ 12 in newer files) */ + if (m->mh == NULL || m->mh->header_length == NULL) { + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + size_t offset = 0; + if (mobi_version > 2) { + offset = 12; + } + mobi_buffer_setpos(buf, *m->mh->header_length + RECORD0_HEADER_LEN + offset); + } else { + /* offset 14 */ + mobi_buffer_setpos(buf, 14); + } + + unsigned char key_enc[KEYSIZE]; + mobi_buffer_getraw(key_enc, buf, KEYSIZE); + mobi_buffer_free_null(buf); + MOBI_RET ret = mobi_pk1_decrypt(key, key_enc, KEYSIZE, INTERNAL_READER_KEY_V1); + return ret; +} + +/** + @brief Get key corresponding to given pid + + @param[in,out] key Key + @param[in] pid PID + @param[in] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmkey_get(unsigned char key[KEYSIZE], const unsigned char *pid, const MOBIData *m) { + MOBI_RET ret; + if (m->rh && m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + ret = mobi_drmkey_get_v1(key, m); + } else { + ret = mobi_drmkey_get_v2(key, pid, m); + } + return ret; +} + +/** + @brief Decrypt buffer with PK1 algorithm + + @param[in,out] out Decrypted buffer + @param[in] in Encrypted buffer + @param[in] length Buffer length + @param[in] m MOBIData structure with loaded key + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_buffer_decrypt(unsigned char *out, const unsigned char *in, const size_t length, const MOBIData *m) { + if (m == NULL || !mobi_has_drmkey(m)) { + return MOBI_INIT_FAILED; + } + MOBIDrm *drm = m->internals; + return mobi_pk1_decrypt(out, in, length, drm->key); +} + +/** + @brief Encrypt buffer with PK1 algorithm + + @param[in,out] out Encrypted buffer + @param[in] in Decrypted buffer + @param[in] length Buffer length + @param[in] m MOBIData structure with loaded key + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_buffer_encrypt(unsigned char *out, const unsigned char *in, const size_t length, const MOBIData *m) { + if (m == NULL || !mobi_has_drmkey(m)) { + return MOBI_INIT_FAILED; + } + + MOBIDrm *drm = m->internals; + return mobi_pk1_encrypt(out, in, length, drm->key); +} + +/** + @brief Calculate pid checksum + + @param[in] pid Pid + @param[out] checksum Calculated checksum + */ +static void mobi_drmpid_checksum(char checksum[2], const unsigned char *pid) { + const char map[] = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"; + const uint8_t map_length = sizeof(map) - 1; + uint32_t crc = (uint32_t) ~m_crc32(0xffffffff, pid, PIDSIZE - 2); + crc ^= (crc >> 16); + for (size_t i = 0; i < 2; i++){ + uint8_t b = crc & 0xff; + uint8_t pos = (b / map_length) ^ (b % map_length); + checksum[i] = map[pos % map_length]; + crc >>= 8; + } +} + +/** + @brief Verify PID + + @param[in] pid PID + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmpid_verify(const unsigned char *pid) { + char checksum[2] = "\0"; + mobi_drmpid_checksum(checksum, pid); + if (memcmp(checksum, &pid[PIDSIZE - 2], 2) == 0) { + return MOBI_SUCCESS; + } + debug_print("checksum: %x%x, pid: %x%x\n", checksum[0], checksum[1], pid[PIDSIZE - 2], pid[PIDSIZE - 1]); + return MOBI_DRM_PIDINV; +} + +/** + @brief Verify serial number + + @param[in] serial Serial number + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_serial_verify(const char *serial) { + const size_t serial_length = strlen(serial); + if (serial_length != SERIALSIZE && serial_length != SERIALLONGSIZE) { + debug_print("Wrong serial length: %zu\n", serial_length); + return MOBI_DRM_PIDINV; + } + return MOBI_SUCCESS; +} + +/** + @brief Calculate PID from device serial number + + @param[in] serial Device serial number + @param[out] pid Pid + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmpid_from_serial(char pid[PIDSIZE + 1], const char *serial) { + memset(pid, 0, PIDSIZE + 1); + MOBI_RET ret = mobi_serial_verify(serial); + if (ret != MOBI_SUCCESS) { + return ret; + } + const char map[] = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"; + unsigned char out[PIDSIZE - 2] = "\0"; + size_t out_length = sizeof(out); + const size_t serial_length = strlen(serial); + if (serial_length == SERIALSIZE) { + out_length--; + pid[out_length] = '*'; + } + uint32_t crc = (uint32_t) ~m_crc32(0xffffffff, (const unsigned char *) serial, (unsigned int) serial_length); + for (size_t i = 0; i < serial_length; i++) { + out[i % out_length] ^= serial[i]; + } + for (size_t i = 0; i < out_length; i++) { + uint8_t b = crc >> (24 - 8 * (i & 3)) & 0xff; + out[i] ^= b; + uint8_t pos = (out[i] >> 7) + ((out[i] >> 5 & 3) ^ (out[i] & 0x1f)); + /* pos max is 32 < map size */ + pid[i] = map[pos]; + } + char checksum[2] = "\0"; + mobi_drmpid_checksum(checksum, (unsigned char *) pid); + memcpy(&pid[PIDSIZE - 2], checksum, 2); + return MOBI_SUCCESS; +} + +/** + @brief Get drm components from EXTH records + + Must be deallocated after use with mobi_exthdrm_free() + + @param[in] m MOBIData structure + @return EXTHDrm structure (NULL or error) + */ +static MOBI_RET mobi_exthdrm_get(MOBIExthDrm **exth_drm, const MOBIData *m) { + if (m == NULL || m->eh == NULL || exth_drm == NULL) { + return MOBI_INIT_FAILED; + } + const MOBIExthHeader *meta = mobi_get_exthrecord_by_tag(m, EXTH_TAMPERKEYS); + + size_t token_size = 0; + unsigned char *token = NULL; + if (meta) { + MOBIBuffer *buf = mobi_buffer_init_null(meta->data, meta->size); + if (buf == NULL) { + return MOBI_MALLOC_FAILED; + } + + while (buf->offset < buf->maxlen) { + uint8_t exth_type = mobi_buffer_get8(buf); // 1 - string, 0 - binary + uint32_t exth_key = mobi_buffer_get32(buf); + const MOBIExthHeader *sub = mobi_get_exthrecord_by_tag(m, exth_key); + if (sub && sub->size) { + size_t size = sub->size; + unsigned char *data = sub->data; + char *data_converted = NULL; + if (exth_type == 1 && mobi_is_cp1252(m)) { + // FIXME: sample needed + size_t out_len = size * 3 + 1; + data_converted = malloc(out_len); + if (data_converted == NULL) { + free(token); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = mobi_cp1252_to_utf8(data_converted, sub->data, &out_len, size); + if (ret == MOBI_SUCCESS) { + data = (unsigned char *) data_converted; + size = out_len; + } + } + size_t offset = token_size; + token_size += size; + unsigned char *tmp = realloc(token, token_size); + if (tmp == NULL) { + free(token); + free(data_converted); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + token = tmp; + memcpy(token + offset, data, size); + free(data_converted); + } + } + mobi_buffer_free_null(buf); + } + + *exth_drm = malloc(sizeof(MOBIExthDrm)); + if (*exth_drm == NULL) { + free(token); + return MOBI_MALLOC_FAILED; + } + (*exth_drm)->data = meta ? meta->data : NULL; + (*exth_drm)->data_size = meta ? meta->size : 0; + (*exth_drm)->token = token; + (*exth_drm)->token_size = token_size; + + return MOBI_SUCCESS; +} + +/** + @brief Free EXTHDrm structure + + @param[in,out] exth_drm EXTHDrm to be freed + */ +static void mobi_free_exthdrm(MOBIExthDrm **exth_drm) { + if (exth_drm) { + if (*exth_drm) { + free((*exth_drm)->token); + (*exth_drm)->token = NULL; + } + free(*exth_drm); + *exth_drm = NULL; + } +} + +/** + @brief Calculate SHA-1 hash for given message + + @param[in] message Message + @param[in] message_length Message length + @param[out] hash Hash + */ +static void mobi_SHA1(unsigned char hash[SHA1_DIGEST_SIZE], size_t message_length, const unsigned char *message) { + SHA1_CTX ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, message, message_length); + SHA1_Final(&ctx, hash); +} + +/** + @brief Calculate PID using device serial and values stored in EXTH records + + @param[in] serial Device serial number + @param[in] m MOBIData structure + @param[out] pid Pid + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmpid_from_serial_exth(char pid[PIDSIZE + 1], const MOBIData *m, const char *serial) { + memset(pid, 0, PIDSIZE + 1); + + MOBI_RET ret = mobi_serial_verify(serial); + if (ret != MOBI_SUCCESS) { + return ret; + } + + MOBIExthDrm *exth_drm = NULL; + ret = mobi_exthdrm_get(&exth_drm, m); + if (ret != MOBI_SUCCESS) { + return ret; + } + const size_t serial_length = strlen(serial); + size_t message_length = serial_length + exth_drm->token_size + exth_drm->data_size; + + unsigned char *message = malloc(message_length); + if (message == NULL) { + mobi_free_exthdrm(&exth_drm); + return MOBI_MALLOC_FAILED; + } + memcpy(message, serial, serial_length); + if (exth_drm->data_size) { + memcpy(&message[serial_length], exth_drm->data, exth_drm->data_size); + } + if (exth_drm->token_size) { + memcpy(&message[serial_length + exth_drm->data_size], exth_drm->token, exth_drm->token_size); + } + mobi_free_exthdrm(&exth_drm); + + unsigned char hash[SHA1_DIGEST_SIZE]; + mobi_SHA1(hash, message_length, message); + free(message); + + int bytes = 8; + uint64_t val = 0; + unsigned char *ptr = hash; + while (bytes--) { + val |= (uint64_t) *ptr++ << (bytes * 8); + } + const char map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (size_t i = 0; i < 8; i++) { + uint8_t pos = (uint64_t) val >> 58; + val <<= 6; + pid[i] = map[pos]; + } + char checksum[2] = "\0"; + mobi_drmpid_checksum(checksum, (unsigned char *) pid); + memcpy(&pid[PIDSIZE - 2], checksum, 2); + return MOBI_SUCCESS; +} + +/** + @brief Store key for encryption in MOBIData stucture. + Pid will be calculated from device serial number. + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] serial Serial + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drmkey_set_serial(MOBIData *m, const char *serial) { + char pid[PIDSIZE + 1]; + MOBI_RET ret = mobi_serial_verify(serial); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_drmpid_from_serial(pid, serial); + debug_print("Device pid: %s\n", pid); + if (ret == MOBI_SUCCESS && (ret = mobi_drmkey_set(m, pid)) == MOBI_SUCCESS) { + return MOBI_SUCCESS; + } + if (ret != MOBI_DRM_PIDINV && ret != MOBI_DRM_EXPIRED && ret != MOBI_DRM_KEYNOTFOUND) { + /* return in case of non-drm error */ + return ret; + } + bool isExpired = (ret == MOBI_DRM_EXPIRED); + ret = mobi_drmpid_from_serial_exth(pid, m, serial); + debug_print("Book pid: %s\n", pid); + if (ret == MOBI_SUCCESS && (ret = mobi_drmkey_set(m, pid) == MOBI_SUCCESS)) { + return MOBI_SUCCESS; + } + return isExpired ? MOBI_DRM_EXPIRED : ret; +} + +/** + @brief Store DRM cookie data in MOBIData stucture + + This data is needed to encrypt main key during DRM applying process + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] pid PID, NULL if not set + @param[in] valid_from Voucher validity start time, 0 if not set + @param[in] valid_to Voucher expire time, MOBI_NOTSET if not set + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_cookie_add(MOBIData *m, const unsigned char *pid, const uint32_t valid_from, const uint32_t valid_to) { + if (valid_from > valid_to) { + return MOBI_PARAM_ERR; + } + if (m->internals == NULL && (m->internals = mobi_drm_init()) == NULL) { + return MOBI_MALLOC_FAILED; + } + MOBIDrm *drm = m->internals; + if (drm->cookies_count == VOUCHERS_COUNT_MAX) { + debug_print("Maximum PID count reached (%d) %s", VOUCHERS_COUNT_MAX, "\n"); + return MOBI_PARAM_ERR; + } + if (drm->cookies_count == 0) { + drm->cookies = malloc(sizeof(*drm->cookies)); + } else { + MOBICookie **tmp = realloc(drm->cookies, (drm->cookies_count + 1) * sizeof(*drm->cookies)); + if (tmp == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + drm->cookies = tmp; + } + + MOBICookie *cookie = calloc(1, sizeof(MOBICookie)); + if (cookie == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + + cookie->valid_from = valid_from; + cookie->valid_to = valid_to; + if (pid) { + cookie->pid = malloc(PIDSIZE); + if (cookie->pid == NULL) { + debug_print("Memory allocation failed%s", "\n"); + free(cookie); + return MOBI_MALLOC_FAILED; + } + memcpy(cookie->pid, pid, PIDSIZE); + } + + drm->cookies[drm->cookies_count++] = cookie; + + return MOBI_SUCCESS; +} + +/** + @brief Store pid for encryption in MOBIData stucture + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] pid PID + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drmpid_add(MOBIData *m, const unsigned char *pid) { + return mobi_cookie_add(m, pid, 0, MOBI_NOTSET); +} + +/** + @brief Adds tamperproof keys record to EXTH header + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] tamperkeys Array of tags to put in tamperproof record + @param[in] tamperkeys_count Tags count + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_tamperkeys_add(MOBIData *m, const MOBIExthTag *tamperkeys, const size_t tamperkeys_count) { + + if (m == NULL) { + return MOBI_INIT_FAILED; + } + if (tamperkeys_count == 0 || tamperkeys == NULL ) { + return MOBI_PARAM_ERR; + } + + // size of buffer is 5 bytes for each array member + const size_t record_size = tamperkeys_count * 5; + if (record_size >= UINT32_MAX) { + debug_print("Too many tamperkeys: %zu\n", record_size); + return MOBI_PARAM_ERR; + } + MOBIBuffer *buf = mobi_buffer_init(record_size); + if (buf == NULL) { + return MOBI_MALLOC_FAILED; + } + + for (size_t i = 0; i < tamperkeys_count; i++) { + MOBIExthHeader *tag = mobi_get_exthrecord_by_tag(m, tamperkeys[i]); + if (tag == NULL) { + debug_print("Missing EXTH record with tag %u\n", tamperkeys[i]); + mobi_buffer_free(buf); + return MOBI_PARAM_ERR; + } + MOBIExthMeta meta = mobi_get_exthtagmeta_by_tag(tamperkeys[i]); + uint8_t tag_type = meta.type == EXTH_STRING ? 1 : 0; + mobi_buffer_add8(buf, tag_type); + mobi_buffer_add32(buf, tamperkeys[i]); + } + + mobi_delete_exthrecord_by_tag(m, EXTH_TAMPERKEYS); + MOBI_RET ret = mobi_add_exthrecord(m, EXTH_TAMPERKEYS, (uint32_t) record_size, buf->data); + + mobi_buffer_free(buf); + + return ret; +} + +/** + @brief Add DRM voucher + + @see mobi_drm_addvoucher + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] serial Device serial number + @param[in] valid_from Voucher validity start time, -1 if not set + @param[in] valid_to Voucher expire time, -1 if not set + @param[in] tamperkeys Array of EXTH tags to include in PID generation, NULL if none + @param[in] tamperkeys_count Count of EXTH tags + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_voucher_add(MOBIData *m, const char *serial, const time_t valid_from, const time_t valid_to, + const MOBIExthTag *tamperkeys, const size_t tamperkeys_count) { + + if (tamperkeys_count) { + mobi_tamperkeys_add(m, tamperkeys, tamperkeys_count); + } + + // calculate PID if serial is provided + char serial_pid[PIDSIZE + 1]; + unsigned char *pid = NULL; + if (serial) { + MOBI_RET ret = mobi_drmpid_from_serial(serial_pid, serial); + debug_print("Pid for device serial %s: %s\n", serial, serial_pid); + if (ret != MOBI_SUCCESS) { + return ret; + } + pid = (unsigned char *) serial_pid; + } + + // convert time values to mobi format + uint32_t from = 0; + if (valid_from > 0 && (size_t) (valid_from / 60) <= UINT32_MAX) { + from = (uint32_t) (valid_from / 60); + } + uint32_t to = MOBI_NOTSET; + if (valid_to >= 0 && (size_t) (valid_to / 60) <= UINT32_MAX) { + to = (uint32_t) (valid_to / 60); + } + + // Verification on Kindles requires both dates to be set but we allow users to set just one. + // Set missing range limit if necessary. + if (from != 0 && to == MOBI_NOTSET) { + to = UINT32_MAX - 1; + } + if (to != MOBI_NOTSET && from == 0) { + from = 1; + } + + return mobi_cookie_add(m, pid, from, to); +} + +/** + @brief Store key for encryption in MOBIData stucture + + In case of encrypted document key is extracted from document. PID may be needed. + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] pid PID, may be NULL in case of encryption type 1, which does not use PID + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drmkey_set(MOBIData *m, const char *pid) { + if (m == NULL || m->rh == NULL) { + return MOBI_INIT_FAILED; + } + + MOBI_RET ret; + unsigned char *drm_pid = (unsigned char *) pid; + if (pid) { + const size_t pid_length = strlen(pid); + if (pid_length != PIDSIZE) { + debug_print("PID size is wrong (%zu)\n", pid_length); + return MOBI_DRM_PIDINV; + } + ret = mobi_drmpid_verify(drm_pid); + if (ret != MOBI_SUCCESS) { + debug_print("PID is invalid%s", "\n"); + return ret; + } + if (!mobi_is_encrypted(m)) { + debug_print("Document not encrypted, adding voucher%s", "\n"); + mobi_drmpid_add(m, drm_pid); + return MOBI_SUCCESS; + } + } + + if (drm_pid && m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + /* PID not needed */ + debug_print("Encryption doesn't require PID%s", "\n"); + drm_pid = NULL; + } + unsigned char key[KEYSIZE]; + ret = mobi_drmkey_get(key, drm_pid, m); + if (ret != MOBI_SUCCESS) { + debug_print("Key not found%s", "\n"); + return ret; + } + ret = mobi_drmkey_init(m, key); + if (ret != MOBI_SUCCESS) { + return ret; + } + + if (m->rh->encryption_type > 1) { + ret = mobi_drmpid_add(m, drm_pid); + } + + return ret; +} + +/** + @brief Remove key from MOBIData structure + + @param[in,out] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drmkey_delete(MOBIData *m) { + if (m == NULL) { + return MOBI_INIT_FAILED; + } + mobi_free_drm(m); + return MOBI_SUCCESS; +} + +/** + @brief Mark document as encrypted + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] encryption_type Encryption type + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drm_set(MOBIData *m, const uint16_t encryption_type) { + + m->rh->encryption_type = encryption_type; + + if (encryption_type == MOBI_ENCRYPTION_V2) { + if (m->mh == NULL) { + return MOBI_DATA_CORRUPT; + } + if (m->mh->drm_size == NULL) { + m->mh->drm_size = malloc(sizeof(uint32_t)); + if (m->mh->drm_size == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + if (m->mh->drm_offset == NULL) { + m->mh->drm_offset = malloc(sizeof(uint32_t)); + if (m->mh->drm_offset == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + if (m->mh->drm_count == NULL) { + m->mh->drm_count = malloc(sizeof(uint32_t)); + if (m->mh->drm_count == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + if (m->mh->drm_flags == NULL) { + m->mh->drm_flags = malloc(sizeof(uint32_t)); + if (m->mh->drm_flags == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + + size_t drm_size = VOUCHERS_SIZE_MIN; + MOBIDrm *drm = m->internals; + if (drm->cookies_count * VOUCHERSIZE > VOUCHERS_SIZE_MIN) { + drm_size = drm->cookies_count * VOUCHERSIZE; + } + *m->mh->drm_size = (uint32_t) drm_size; + /* initial offset set to unknown */ + *m->mh->drm_offset = MOBI_NOTSET; + /* flags: b0 = 1 internal key? */ + *m->mh->drm_flags = 2048; + *m->mh->drm_count = drm->cookies_count; + } + + return MOBI_SUCCESS; +} + +/** + @brief Mark document as decrypted + + @param[in,out] m MOBIData structure with raw data and metadata + */ +static void mobi_drm_unset(MOBIData *m) { + if (m->rh->encryption_type == MOBI_ENCRYPTION_V2 && m->mh) { + if (m->mh->drm_offset) { + *m->mh->drm_offset = MOBI_NOTSET; + } + if (m->mh->drm_size) { + *m->mh->drm_size = 0; + } + if (m->mh->drm_count) { + *m->mh->drm_count = 0; + } + if (m->mh->drm_flags) { + *m->mh->drm_flags = 0; + } + } + m->rh->encryption_type = MOBI_ENCRYPTION_NONE; + + mobi_drmkey_delete(m); +} + +/** + @brief Decrypt or encrypt records + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] is_decryption Should we decrypt or encrypt + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drm_records(MOBIData *m, const bool is_decryption) { + + /* FIXME: hybrid files are not encrypted, are they? */ + size_t text_rec_index = 1; + + if (!is_decryption) { + const size_t offset = mobi_get_kf8offset(m); + if (m->rh == NULL || m->rh->text_record_count == 0) { + debug_print("%s", "Text records not found in MOBI header\n"); + return MOBI_DATA_CORRUPT; + } + text_rec_index = 1 + offset; + } + + size_t text_rec_count = m->rh->text_record_count; + const uint16_t compression_type = m->rh->compression_type; + uint16_t extra_flags = 0; + if (m->mh && m->mh->extra_flags) { + extra_flags = *m->mh->extra_flags; + } + if (compression_type != MOBI_COMPRESSION_HUFFCDIC) { + /* encrypt also multibyte extra data */ + extra_flags &= 0xfffe; + } + /* get first text record */ + const MOBIPdbRecord *curr = mobi_get_record_by_seqnumber(m, text_rec_index); + + while (text_rec_count-- && curr) { + size_t extra_size = 0; + if (extra_flags) { + extra_size = mobi_get_record_extrasize(curr, extra_flags); + if (extra_size == MOBI_NOTSET || extra_size >= curr->size) { + return MOBI_DATA_CORRUPT; + } + } + + size_t decrypt_size = curr->size - extra_size;; + unsigned char *decrypted = malloc(decrypt_size); + if (decrypted == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + + MOBI_RET ret; + if (is_decryption) { + ret = mobi_buffer_decrypt(decrypted, curr->data, decrypt_size, m); + } else { + ret = mobi_buffer_encrypt(decrypted, curr->data, decrypt_size, m); + } + if (ret != MOBI_SUCCESS) { + free(decrypted); + return ret; + } + memcpy(curr->data, decrypted, decrypt_size); + free(decrypted); + curr = curr->next; + } + + return MOBI_SUCCESS; +} + +/** + @brief Decrypt document. + + It is not necessary to call this function in order to parse encrypted document. + If pid is set document will be decrypted automatically during uncompression. + The reason for this function is to load and resave decrypted document without parsing. + + @param[in,out] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_decrypt(MOBIData *m) { + if (m == NULL) { + return MOBI_INIT_FAILED; + } + if (!mobi_is_encrypted(m)) { + debug_print("%s\n", "Document not encrypted"); + return MOBI_SUCCESS; + } + if (m->rh == NULL || m->rh->text_record_count == 0) { + debug_print("%s\n", "No records to decrypt"); + return MOBI_SUCCESS; + } + + MOBI_RET ret; + if (!mobi_has_drmkey(m)) { + /* try to set key */ + debug_print("%s\n", "Trying to set key for encryption without device PID"); + ret = mobi_drm_setkey(m, NULL); + if (ret != MOBI_SUCCESS) { + debug_print("%s\n", "Key setting failed"); + return ret; + } + } + + ret = mobi_drm_records(m, true); + if (ret != MOBI_SUCCESS) { + return ret; + } + + mobi_drm_unset(m); + + return MOBI_SUCCESS; +} + +/** + @brief Serialize encryption voucher + + This supports key types 1 and 3, used on eInk devices + + @param[in,out] buf Output buffer + @param[in] key Main encryption key + @param[in] cookie Voucher cookie data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_voucher_serialize(MOBIBuffer *buf, const unsigned char *key, const MOBICookie *cookie) { + + MOBI_RET ret; + // Notes on reversing flags + // 5 first bits (flags & 0x1f) mean key type: + // type 1 - device serial + exth key, + // type 2 - device generic type id (no samples, not used any more?), + // type 3 – internal key. + // If drm flags in mobi header have bit 0 set then additional user password is used (probably not used any more). + // In case of password protection temporary key is additionally encrypted with password (bit 4 must be set?) + // In case of key types 1 and 2 bit 11 (0x800) must be set, unless there is additional password + // Bit 6 (0x40) must be set, otherwise found key is not used. + uint32_t flags; + unsigned char pidkey[KEYSIZE] = "\0"; + if (cookie->pid) { + flags = 0x841; // key type 1 + memcpy(pidkey, cookie->pid, PIDSIZE - 2); + ret = mobi_pk1_encrypt(pidkey, pidkey, KEYSIZE, INTERNAL_READER_KEY); + if (ret != MOBI_SUCCESS) { + return ret; + } + } else { + memcpy(pidkey, INTERNAL_READER_KEY, KEYSIZE); + flags = 0x43; // key type 3 + } + + uint8_t pidkey_checksum = mobi_drmkey_checksum(pidkey); + uint32_t verification = 0x43; // always same in real files, why??? + + mobi_buffer_add32(buf, verification); // 0: verification + mobi_buffer_add32(buf, VOUCHERSIZE); // 4: size + mobi_buffer_add32(buf, 1); // 8: always 1 ? + mobi_buffer_add8(buf, pidkey_checksum); // 12: pid checksum + mobi_buffer_addzeros(buf, 3); + // start of encrypted part - cookie + unsigned char *cookie_buf = buf->data + buf->offset; + mobi_buffer_add32(buf, verification); // 16: verification + mobi_buffer_add32(buf, flags); // 20: flags + mobi_buffer_addraw(buf, key, KEYSIZE); // 24: key + mobi_buffer_add32(buf, cookie->valid_to); // 40: valid to + mobi_buffer_add32(buf, cookie->valid_from); // 44: valid from + + ret = mobi_pk1_encrypt(cookie_buf, cookie_buf, COOKIESIZE, pidkey); + if (ret != MOBI_SUCCESS) { + return ret; + } + + return MOBI_SUCCESS; +} + +/** + @brief Serialize encryption scheme version 2 + + @param[in,out] buf Output buffer + @param[in] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_serialize_v2(MOBIBuffer *buf, const MOBIData *m) { + if (!m || !m->mh || m->internals == NULL) { + return MOBI_INIT_FAILED; + } + + size_t saved_offset = buf->offset; + + mobi_buffer_setpos(buf, *m->mh->drm_offset); + + MOBIDrm *drm = m->internals; + for (size_t i = 0; i < drm->cookies_count; i++) { + MOBI_RET ret = mobi_voucher_serialize(buf, drm->key, drm->cookies[i]); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + size_t cookies_count_min = VOUCHERS_SIZE_MIN / VOUCHERSIZE; + if (drm->cookies_count < cookies_count_min) { + // pad with zeros + mobi_buffer_addzeros(buf, (cookies_count_min - drm->cookies_count) * VOUCHERSIZE); + } + + mobi_buffer_setpos(buf, saved_offset); + + return MOBI_SUCCESS; +} + +/** + @brief Serialize encryption scheme version 1 + + @param[in,out] buf Output buffer + @param[in] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_serialize_v1(MOBIBuffer *buf, const MOBIData *m) { + + size_t saved_offset = buf->offset; + + size_t mobi_version = mobi_get_fileversion(m); + + if (mobi_version > 1) { + /* offset mobi header + record 0 header (+ 12 in newer files) */ + if (m->mh == NULL || m->mh->header_length == NULL) { + return MOBI_DATA_CORRUPT; + } + size_t offset = 0; + if (mobi_version > 2) { + offset = 12; + } + mobi_buffer_setpos(buf, *m->mh->header_length + RECORD0_HEADER_LEN + offset); + } else { + /* offset 14 */ + mobi_buffer_setpos(buf, 14); + } + + MOBIDrm *drm = m->internals; + + uint8_t key_type = 1; // 1 - simple, 2 - verification password, 4 - verification key + unsigned char *key_offset = buf->data + buf->offset; + mobi_buffer_addraw(buf, drm->key, KEYSIZE); // 0 + mobi_buffer_addzeros(buf, 1); // 16 + // meta + unsigned char *meta_offset = buf->data + buf->offset; + mobi_buffer_add8(buf, key_type); // 17: key type + mobi_buffer_addzeros(buf, 1); // 18 + // simple: no verification + mobi_buffer_addzeros(buf, 32); // 19: password + // 25: verfication key + + MOBI_RET ret = mobi_pk1_encrypt(key_offset, key_offset, KEYSIZE + 1, INTERNAL_READER_KEY_V1); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_pk1_encrypt(meta_offset, meta_offset, 34, drm->key); + if (ret != MOBI_SUCCESS) { + return ret; + } + + mobi_buffer_setpos(buf, saved_offset); + + return MOBI_SUCCESS; +} + +/** + @brief Initializes random key + + @param[in,out] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_drm_generate_key(MOBIData *m) { + + unsigned char buf[KEYSIZE]; + + MOBI_RET ret = mobi_randombytes(buf, KEYSIZE); + if (ret != MOBI_SUCCESS) { + debug_print("Getting random buffer failed%s", "\n"); + return ret; + } + + return mobi_drmkey_init(m, buf); +} + +/** + @brief Encrypt document + + DRM vouchers must be added in order to use device serial number in encryption + + @param[in,out] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_encrypt(MOBIData *m) { + + if (m == NULL) { + return MOBI_INIT_FAILED; + } + + uint16_t encryption_type = MOBI_ENCRYPTION_V2; + if (mobi_get_fileversion(m) < 4 || m->eh == NULL) { + encryption_type = MOBI_ENCRYPTION_V1; + } + debug_print("Encryption type: %u\n", encryption_type); + + MOBI_RET ret; + if (!mobi_has_drmkey(m)) { + ret = mobi_drm_generate_key(m); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + + if (encryption_type == MOBI_ENCRYPTION_V2 && !mobi_has_drmcookies(m)) { + mobi_cookie_add(m, NULL, 0, MOBI_NOTSET); + } + + ret = mobi_drm_records(m, false); + if (ret != MOBI_SUCCESS) { + return ret; + } + + return mobi_drm_set(m, encryption_type); +} diff --git a/Charcoal/Charcoal/libmobi-public/src/encryption.h b/Charcoal/Charcoal/libmobi-public/src/encryption.h new file mode 100644 index 0000000..1ee3e39 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/encryption.h @@ -0,0 +1,46 @@ +/** @file encryption.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_encryption_h +#define mobi_encryption_h + +#include "config.h" +#include "mobi.h" + +/** + @brief Drm cookie data + */ +typedef struct { + unsigned char *pid; /**< PIDs for decryption, NULL if not set */ + uint32_t valid_from; /**< validity period start time, unix time in minutes, 0 if not set */ + uint32_t valid_to; /**< validity period end time, unix time in minutes, MOBI_NOTSET if not set */ +} MOBICookie; + +/** + @brief Drm data + */ + +typedef struct { + unsigned char *key; /**< key for decryption, NULL if not set */ + uint32_t cookies_count; /**< Cookies count */ + MOBICookie **cookies; /**< DRM cookie */ +} MOBIDrm; + +void mobi_free_drm(MOBIData *m); +MOBI_RET mobi_buffer_decrypt(unsigned char *out, const unsigned char *in, const size_t length, const MOBIData *m); +MOBI_RET mobi_drmkey_set(MOBIData *m, const char *pid); +MOBI_RET mobi_drmkey_set_serial(MOBIData *m, const char *serial); +MOBI_RET mobi_drmkey_delete(MOBIData *m); +MOBI_RET mobi_voucher_add(MOBIData *m, const char *serial, const time_t valid_from, const time_t valid_to, + const MOBIExthTag *tamperkeys, const size_t tamperkeys_count); +MOBI_RET mobi_drm_serialize_v1(MOBIBuffer *buf, const MOBIData *m); +MOBI_RET mobi_drm_serialize_v2(MOBIBuffer *buf, const MOBIData *m); + +#endif /* defined(mobi_encryption_h) */ diff --git a/Charcoal/Charcoal/libmobi-public/src/index.c b/Charcoal/Charcoal/libmobi-public/src/index.c new file mode 100644 index 0000000..f8ad74f --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/index.c @@ -0,0 +1,1092 @@ +/** @file index.c + * @brief Functions to parse index records + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#define _GNU_SOURCE 1 +#ifndef __USE_BSD +#define __USE_BSD /* for strdup on linux/glibc */ +#endif + +#include +#include +#include + +#include "index.h" +#include "util.h" +#include "memory.h" +#include "debug.h" +#include "buffer.h" + + + +/** + @brief Read index entry label from buffer pointing at index record data + + @param[in,out] output Output buffer (INDX_LABEL_SIZEMAX + 1 bytes) + @param[in,out] buf MOBIBuffer structure, offset pointing at index entry label + @param[in] length Number of bytes to be read + @param[in] has_ligatures Decode ligatures if true + @return Length of output string (without null terminator), on error buf->error set to MOBI_RET status + */ +size_t mobi_indx_get_label(unsigned char *output, MOBIBuffer *buf, const size_t length, const size_t has_ligatures) { + if (!output) { + buf->error = MOBI_PARAM_ERR; + return 0; + } + if (buf->offset + length > buf->maxlen) { + debug_print("%s", "End of buffer\n"); + buf->error = MOBI_BUFFER_END; + return 0; + } + const unsigned char replacement = 0x3f; + size_t output_length = 0; + size_t i = 0; + while (i < length && output_length < INDX_LABEL_SIZEMAX) { + unsigned char c = mobi_buffer_get8(buf); + i++; + if (c == 0) { + /* FIXME: is it safe to replace zeroes? */ + debug_print("Invalid character: %u\n", c); + c = replacement; + } + if (c <= 5 && has_ligatures) { + unsigned char c2 = mobi_buffer_get8(buf); + c = mobi_ligature_to_cp1252(c, c2); + if (c == 0) { + debug_print("Invalid ligature sequence%s", "\n"); + mobi_buffer_seek(buf, -1); + c = replacement; + } else { + i++; + } + } + *output++ = c; + output_length++; + } + *output = '\0'; + return output_length; +} + +/** + @brief Parser of ORDT section of INDX record + + @param[in,out] buf MOBIBuffer structure, offset pointing at beginning of TAGX section + @param[in,out] ordt MOBIOrdt structure to be filled by the function + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_parse_ordt(MOBIBuffer *buf, MOBIOrdt *ordt) { + /* read ORDT1 */ + mobi_buffer_setpos(buf, ordt->ordt1_pos); + if (mobi_buffer_match_magic(buf, ORDT_MAGIC)) { + debug_print("%s\n", "ORDT1 section found"); + mobi_buffer_seek(buf, 4); + if (ordt->offsets_count + buf->offset > buf->maxlen) { + debug_print("ORDT1 section too long (%zu)", ordt->offsets_count); + return MOBI_DATA_CORRUPT; + } + ordt->ordt1 = malloc(ordt->offsets_count * sizeof(*ordt->ordt1)); + if (ordt->ordt1 == NULL) { + debug_print("%s", "Memory allocation failed for ORDT1 offsets\n"); + return MOBI_MALLOC_FAILED; + } + size_t i = 0; + while (i < ordt->offsets_count) { + ordt->ordt1[i++] = mobi_buffer_get8(buf); + } + debug_print("ORDT1: read %zu entries\n", ordt->offsets_count); + } + /* read ORDT2 */ + mobi_buffer_setpos(buf, ordt->ordt2_pos); + if (mobi_buffer_match_magic(buf, ORDT_MAGIC)) { + debug_print("%s\n", "ORDT2 section found"); + mobi_buffer_seek(buf, 4); + if (ordt->offsets_count * 2 + buf->offset > buf->maxlen) { + debug_print("ORDT2 section too long (%zu)", ordt->offsets_count); + return MOBI_DATA_CORRUPT; + } + ordt->ordt2 = malloc(ordt->offsets_count * sizeof(*ordt->ordt2)); + if (ordt->ordt2 == NULL) { + debug_print("%s", "Memory allocation failed for ORDT2 offsets\n"); + return MOBI_MALLOC_FAILED; + } + size_t i = 0; + while (i < ordt->offsets_count) { + ordt->ordt2[i++] = mobi_buffer_get16(buf); + } + debug_print("ORDT2: read %zu entries\n", ordt->offsets_count); + } + return MOBI_SUCCESS; +} + +/** + @brief Parser of TAGX section of INDX record + + @param[in,out] buf MOBIBuffer structure, offset pointing at beginning of TAGX section + @param[in,out] tagx MOBITagx structure to be filled by the function + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_parse_tagx(MOBIBuffer *buf, MOBITagx *tagx) { + tagx->control_byte_count = 0; + tagx->tags_count = 0; + tagx->tags = NULL; + mobi_buffer_seek(buf, 4); /* skip header */ + uint32_t tagx_record_length = mobi_buffer_get32(buf); + if (tagx_record_length < 12) { + debug_print("INDX record too short: %u\n", tagx_record_length); + return MOBI_DATA_CORRUPT; + } + tagx->control_byte_count = mobi_buffer_get32(buf); + tagx_record_length -= 12; + if (tagx_record_length + buf->offset > buf->maxlen) { + debug_print("INDX record too long: %u\n", tagx_record_length); + return MOBI_DATA_CORRUPT; + } + tagx->tags = malloc(tagx_record_length * sizeof(TAGXTags)); + if (tagx->tags == NULL) { + debug_print("%s", "Memory allocation failed for TAGX tags\n"); + return MOBI_MALLOC_FAILED; + } + size_t i = 0; + const size_t tagx_data_length = tagx_record_length / 4; + size_t control_byte_count = 0; + while (i < tagx_data_length) { + tagx->tags[i].tag = mobi_buffer_get8(buf); + tagx->tags[i].values_count = mobi_buffer_get8(buf); + tagx->tags[i].bitmask = mobi_buffer_get8(buf); + const uint8_t control_byte = mobi_buffer_get8(buf); + if (control_byte) { control_byte_count++; } + tagx->tags[i].control_byte = control_byte; + debug_print("tagx[%zu]:\t%i\t%i\t%i\t%i\n", i, tagx->tags[i].tag, tagx->tags[i].values_count, tagx->tags[i].bitmask, control_byte); + i++; + } + if (tagx->control_byte_count != control_byte_count) { + debug_print("Wrong count of control bytes: %zu != %zu\n", tagx->control_byte_count, control_byte_count); + free(tagx->tags); + tagx->tags = NULL; + tagx->control_byte_count = 0; + return MOBI_DATA_CORRUPT; + } + tagx->tags_count = i; + return MOBI_SUCCESS; +} + +/** + @brief Parser of IDXT section of INDX record + + @param[in,out] buf MOBIBuffer structure, offset pointing at beginning of TAGX section + @param[in,out] idxt MOBITagx structure to be filled by the function + @param[in] entries_count Number of index entries + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_parse_idxt(MOBIBuffer *buf, MOBIIdxt *idxt, const size_t entries_count) { + const uint32_t idxt_offset = (uint32_t) buf->offset; + idxt->offsets_count = 0; + char idxt_magic[5]; + mobi_buffer_getstring(idxt_magic, buf, 4); + if (strncmp(idxt_magic, IDXT_MAGIC, 4) != 0) { + debug_print("IDXT wrong magic: %s\n", idxt_magic); + return MOBI_DATA_CORRUPT; + } + size_t i = 0; + while (i < entries_count) { + /* entry offsets */ + idxt->offsets[i++] = mobi_buffer_get16(buf); + } + /* last entry end position is IDXT tag offset */ + idxt->offsets[i] = idxt_offset; + idxt->offsets_count = i; + return MOBI_SUCCESS; +} + +/** + @brief Get encoded character from dictionary index + The characters are offsets into ORDT table + + @param[in] ordt MOBIOrdt structure (ORDT data and metadata) + @param[in,out] buf MOBIBuffer structure with index data + @param[in,out] offset Value read from buffer + @return Number of bytes read (zero in case of error) + */ +size_t mobi_ordt_getbuffer(const MOBIOrdt *ordt, MOBIBuffer *buf, uint16_t *offset) { + size_t i = 0; + if (ordt->type == 1) { + *offset = mobi_buffer_get8(buf); + i++; + } else { + *offset = mobi_buffer_get16(buf); + i += 2; + } + return i; +} + +/** + @brief Fetch UTF-16 value from ORDT2 table + + @param[in] ordt MOBIOrdt structure (ORDT data and metadata) + @param[in] offset Offset in ORDT2 table + @return UTF-16 code point + */ +uint16_t mobi_ordt_lookup(const MOBIOrdt *ordt, const uint16_t offset) { + uint16_t utf16; + if (offset < ordt->offsets_count) { + utf16 = ordt->ordt2[offset]; + } else { + utf16 = offset; + } + return utf16; +} + +/** + @brief Get UTF-8 string from buffer, decoded by lookups in ORDT2 table + + @param[in] ordt MOBIOrdt structure (ORDT data and metadata) + @param[in,out] buf MOBIBuffer structure with input string + @param[in,out] output Output buffer (INDX_LABEL_SIZEMAX + 1 bytes) + @param[in] length Length of input string contained in buf + @return Length of output string (without null terminator) + */ +size_t mobi_getstring_ordt(const MOBIOrdt *ordt, MOBIBuffer *buf, unsigned char *output, size_t length) { + size_t i = 0; + size_t output_length = 0; + const uint32_t bytemask = 0xbf; + const uint32_t bytemark = 0x80; + const uint32_t uni_replacement = 0xfffd; + const uint32_t surrogate_offset = 0x35fdc00; + static const uint8_t init_byte[7] = { 0x00, 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc }; + while (i < length) { + uint16_t offset; + i += mobi_ordt_getbuffer(ordt, buf, &offset); + uint32_t codepoint = mobi_ordt_lookup(ordt, offset); + if (codepoint <= 5) { + size_t k = mobi_ordt_getbuffer(ordt, buf, &offset); + uint32_t codepoint2 = mobi_ordt_lookup(ordt, offset); + codepoint = mobi_ligature_to_utf16(codepoint, codepoint2); + if (codepoint == uni_replacement) { + /* rewind buffer to codepoint2 */ + debug_print("Invalid ligature sequence%s", "\n"); + mobi_buffer_seek(buf, - (int) k); + } else { + i += k; + } + } + /* convert UTF-16 surrogates into UTF-32 */ + if (codepoint >= 0xd800 && codepoint <= 0xdbff) { + size_t k = mobi_ordt_getbuffer(ordt, buf, &offset); + uint32_t codepoint2 = mobi_ordt_lookup(ordt, offset); + if (codepoint2 >= 0xdc00 && codepoint2 <= 0xdfff) { + i += k; + codepoint = (codepoint << 10) + codepoint2 - surrogate_offset; + } else { + /* illegal unpaired high surrogate */ + /* rewind buffer to codepoint2 */ + debug_print("Invalid code point: %u\n", codepoint); + mobi_buffer_seek(buf, - (int) k); + codepoint = uni_replacement; + } + } + if ((codepoint >= 0xdc00 && codepoint <= 0xdfff) /* unpaired low surrogate */ + || (codepoint >= 0xfdd0 && codepoint <= 0xfdef) /* invalid characters */ + || (codepoint & 0xfffe) == 0xfffe /* reserved characters */ + || codepoint == 0 /* remove zeroes */) { + codepoint = uni_replacement; + debug_print("Invalid code point: %u\n", codepoint); + } + /* Conversion routine based on unicode's ConvertUTF.c */ + size_t bytes; + if (codepoint < 0x80) { bytes = 1; } + else if (codepoint < 0x800) { bytes = 2; } + else if (codepoint < 0x10000) { bytes = 3; } + else if (codepoint < 0x110000) { bytes = 4; } + else { + bytes = 3; + codepoint = uni_replacement; + debug_print("Invalid code point: %u\n", codepoint); + } + if (output_length + bytes >= INDX_LABEL_SIZEMAX) { + debug_print("%s\n", "INDX label too long"); + break; + } + output += bytes; + switch (bytes) { + case 4: *--output = (uint8_t)((codepoint | bytemark) & bytemask); codepoint >>= 6; /* falls through */ + case 3: *--output = (uint8_t)((codepoint | bytemark) & bytemask); codepoint >>= 6; /* falls through */ + case 2: *--output = (uint8_t)((codepoint | bytemark) & bytemask); codepoint >>= 6; /* falls through */ + case 1: *--output = (uint8_t)(codepoint | init_byte[bytes]); + } + output += bytes; + output_length += bytes; + } + *output = '\0'; + return output_length; +} + +/** + @brief Parser of INDX index entry + + @param[in,out] indx MOBIIndx structure, to be filled with parsed data + @param[in] idxt MOBIIdxt structure with parsed IDXT index + @param[in] tagx MOBITagx structure with parsed TAGX index + @param[in,out] buf MOBIBuffer structure with index data + @param[in] curr_number Sequential number of an index entry for current record + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_parse_index_entry(MOBIIndx *indx, const MOBIIdxt idxt, const MOBITagx *tagx, const MOBIOrdt *ordt, MOBIBuffer *buf, const size_t curr_number) { + if (indx == NULL) { + debug_print("%s", "INDX structure not initialized\n"); + return MOBI_INIT_FAILED; + } + const size_t entry_offset = indx->entries_count; + const size_t entry_length = idxt.offsets[curr_number + 1] - idxt.offsets[curr_number]; + mobi_buffer_setpos(buf, idxt.offsets[curr_number]); + size_t entry_number = curr_number + entry_offset; + if (entry_number >= indx->total_entries_count) { + debug_print("Entry number beyond array: %zu\n", entry_number); + return MOBI_DATA_CORRUPT; + } + /* save original record maxlen */ + const size_t buf_maxlen = buf->maxlen; + if (buf->offset + entry_length >= buf_maxlen) { + debug_print("Entry length too long: %zu\n", entry_length); + return MOBI_DATA_CORRUPT; + } + buf->maxlen = buf->offset + entry_length; + size_t label_length = mobi_buffer_get8(buf); + if (label_length > entry_length) { + debug_print("Label length too long: %zu\n", label_length); + return MOBI_DATA_CORRUPT; + } + char text[INDX_LABEL_SIZEMAX + 1]; + /* FIXME: what is ORDT1 for? */ + if (ordt->ordt2) { + label_length = mobi_getstring_ordt(ordt, buf, (unsigned char*) text, label_length); + } else { + label_length = mobi_indx_get_label((unsigned char*) text, buf, label_length, indx->ligt_entries_count); + if (buf->error != MOBI_SUCCESS) { + debug_print("Buffer error reading label: %d\n", buf->error); + return MOBI_DATA_CORRUPT; + } + } + indx->entries[entry_number].label = malloc(label_length + 1); + if (indx->entries[entry_number].label == NULL) { + debug_print("Memory allocation failed (%zu bytes)\n", label_length); + return MOBI_MALLOC_FAILED; + } + strncpy(indx->entries[entry_number].label, text, label_length + 1); + //debug_print("tag label[%zu]: %s\n", entry_number, indx->entries[entry_number].label); + unsigned char *control_bytes; + control_bytes = buf->data + buf->offset; + mobi_buffer_seek(buf, (int) tagx->control_byte_count); + indx->entries[entry_number].tags_count = 0; + indx->entries[entry_number].tags = NULL; + if (tagx->tags_count > 0) { + typedef struct { + uint8_t tag; + uint8_t tag_value_count; + uint32_t value_count; + uint32_t value_bytes; + } MOBIPtagx; + MOBIPtagx *ptagx = malloc(tagx->tags_count * sizeof(MOBIPtagx)); + if (ptagx == NULL) { + debug_print("Memory allocation failed (%zu bytes)\n", tagx->tags_count * sizeof(MOBIPtagx)); + free(indx->entries[entry_number].label); + indx->entries[entry_number].label = NULL; + return MOBI_MALLOC_FAILED; + } + uint32_t ptagx_count = 0; + size_t len; + size_t i = 0; + while (i < tagx->tags_count) { + if (tagx->tags[i].control_byte == 1) { + control_bytes++; + i++; + continue; + } + uint32_t value = control_bytes[0] & tagx->tags[i].bitmask; + if (value != 0) { + /* FIXME: is it safe to use MOBI_NOTSET? */ + uint32_t value_count = MOBI_NOTSET; + uint32_t value_bytes = MOBI_NOTSET; + /* all bits of masked value are set */ + if (value == tagx->tags[i].bitmask) { + /* more than 1 bit set */ + if (mobi_bitcount(tagx->tags[i].bitmask) > 1) { + /* read value bytes from entry */ + len = 0; + value_bytes = mobi_buffer_get_varlen(buf, &len); + } else { + value_count = 1; + } + } else { + uint8_t mask = tagx->tags[i].bitmask; + while ((mask & 1) == 0) { + mask >>= 1; + value >>= 1; + } + value_count = value; + } + ptagx[ptagx_count].tag = tagx->tags[i].tag; + ptagx[ptagx_count].tag_value_count = tagx->tags[i].values_count; + ptagx[ptagx_count].value_count = value_count; + ptagx[ptagx_count].value_bytes = value_bytes; + ptagx_count++; + } + i++; + } + indx->entries[entry_number].tags = malloc(tagx->tags_count * sizeof(MOBIIndexTag)); + if (indx->entries[entry_number].tags == NULL) { + debug_print("Memory allocation failed (%zu bytes)\n", tagx->tags_count * sizeof(MOBIIndexTag)); + free(indx->entries[entry_number].label); + indx->entries[entry_number].label = NULL; + free(ptagx); + return MOBI_MALLOC_FAILED; + } + i = 0; + while (i < ptagx_count) { + uint32_t tagvalues_count = 0; + /* FIXME: is it safe to use MOBI_NOTSET? */ + /* value count is set */ + uint32_t tagvalues[INDX_TAGVALUES_MAX]; + if (ptagx[i].value_count != MOBI_NOTSET) { + size_t count = ptagx[i].value_count * ptagx[i].tag_value_count; + while (count-- && tagvalues_count < INDX_TAGVALUES_MAX) { + len = 0; + const uint32_t value_bytes = mobi_buffer_get_varlen(buf, &len); + tagvalues[tagvalues_count++] = value_bytes; + } + /* value count is not set */ + } else { + /* read value_bytes bytes */ + len = 0; + while (len < ptagx[i].value_bytes && tagvalues_count < INDX_TAGVALUES_MAX) { + const uint32_t value_bytes = mobi_buffer_get_varlen(buf, &len); + tagvalues[tagvalues_count++] = value_bytes; + } + } + if (tagvalues_count) { + const size_t arr_size = tagvalues_count * sizeof(*indx->entries[entry_number].tags[i].tagvalues); + indx->entries[entry_number].tags[i].tagvalues = malloc(arr_size); + if (indx->entries[entry_number].tags[i].tagvalues == NULL) { + debug_print("Memory allocation failed (%zu bytes)\n", arr_size); + free(indx->entries[entry_number].label); + indx->entries[entry_number].label = NULL; + for (size_t j = 0; j < i; j++) { + free(indx->entries[entry_number].tags[j].tagvalues); + } + free(indx->entries[entry_number].tags); + indx->entries[entry_number].tags = NULL; + free(ptagx); + return MOBI_MALLOC_FAILED; + } + memcpy(indx->entries[entry_number].tags[i].tagvalues, tagvalues, arr_size); + } else { + indx->entries[entry_number].tags[i].tagvalues = NULL; + } + indx->entries[entry_number].tags[i].tagid = ptagx[i].tag; + indx->entries[entry_number].tags[i].tagvalues_count = tagvalues_count; + indx->entries[entry_number].tags_count++; + i++; + } + free(ptagx); + } + /* restore buffer maxlen */ + buf->maxlen = buf_maxlen; + return MOBI_SUCCESS; +} + +/** + @brief Parser of INDX record + + @param[in] indx_record MOBIPdbRecord structure with INDX record + @param[in,out] indx MOBIIndx structure to be filled with parsed entries + @param[in,out] tagx MOBITagx structure, will be filled with parsed TAGX section data if present in the INDX record, otherwise TAGX data will be used to parse the record + @param[in,out] ordt MOBIOrdt structure, will be filled with parsed ORDT sections + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_indx(const MOBIPdbRecord *indx_record, MOBIIndx *indx, MOBITagx *tagx, MOBIOrdt *ordt) { + if (indx_record == NULL || indx == NULL || tagx == NULL || ordt == NULL) { + debug_print("%s", "index structure not initialized\n"); + return MOBI_INIT_FAILED; + } + MOBI_RET ret = MOBI_SUCCESS; + MOBIBuffer *buf = mobi_buffer_init_null(indx_record->data, indx_record->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char indx_magic[5]; + mobi_buffer_getstring(indx_magic, buf, 4); /* 0: INDX magic */ + const uint32_t header_length = mobi_buffer_get32(buf); /* 4: header length */ + if (strncmp(indx_magic, INDX_MAGIC, 4) != 0 || + header_length == 0 || header_length > indx_record->size) { + debug_print("INDX wrong magic: %s or header length: %u\n", indx_magic, header_length); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_seek(buf, 4); /* 8: unk, usually zeroes */ + const uint32_t type = mobi_buffer_get32(buf); /* 12: 0 - normal, 2 - inflection */ + mobi_buffer_seek(buf, 4); /* 16: unk */ + const uint32_t idxt_offset = mobi_buffer_get32(buf); /* 20: IDXT offset */ + const uint32_t entries_count = mobi_buffer_get32(buf); /* 24: entries count */ + if (entries_count > INDX_RECORD_MAXCNT) { + debug_print("Too many index entries (%u)\n", entries_count); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* if record contains TAGX section, read it (and ORDT) and return */ + if (mobi_buffer_match_magic_offset(buf, TAGX_MAGIC, header_length) && indx->total_entries_count == 0) { + buf->maxlen = header_length; + /* TAGX metadata */ + uint32_t encoding = mobi_buffer_get32(buf); /* 28: encoding */ + if (encoding == MOBI_NOTSET) { encoding = MOBI_CP1252; } + mobi_buffer_seek(buf, 4); /* 32 */ + const uint32_t total_entries_count = mobi_buffer_get32(buf); /* 36: total entries count */ + if (total_entries_count > INDX_TOTAL_MAXCNT) { + debug_print("Too many total index entries (%u)\n", total_entries_count); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + uint32_t ordt_offset = mobi_buffer_get32(buf); /* 40: ORDT offset; currently not used */ + if (ordt_offset + ORDT_RECORD_MAXCNT + 4 > indx_record->size) { + ordt_offset = 0; + } + uint32_t ligt_offset = mobi_buffer_get32(buf); /* 44: LIGT offset; currently static table used instead */ + uint32_t ligt_entries_count = mobi_buffer_get32(buf); /* 48: LIGT entries count */ + if (ligt_offset + 4 * ligt_entries_count + 4 > indx_record->size) { + ligt_offset = 0; + ligt_entries_count = 0; + } + const uint32_t cncx_records_count = mobi_buffer_get32(buf); /* 52: CNCX entries count */ + if (cncx_records_count > CNCX_RECORD_MAXCNT) { + debug_print("Too many CNCX records (%u)\n", cncx_records_count); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* 56: unk count */ + /* 60-148: phonetizer */ + uint32_t ordt_type = 0; + uint32_t ordt_entries_count = 0; + uint32_t ordt1_offset = 0; + uint32_t ordt2_offset = 0; + uint32_t index_name_offset = 0; + uint32_t index_name_length = 0; + if (header_length >= 180) { + mobi_buffer_setpos(buf, 164); + ordt_type = mobi_buffer_get32(buf); /* 164: ORDT type */ + ordt_entries_count = mobi_buffer_get32(buf); /* 168: ORDT entries count */ + ordt1_offset = mobi_buffer_get32(buf); /* 172: ORDT1 offset; currently not used */ + ordt2_offset = mobi_buffer_get32(buf); /* 176: ORDT2 offset */ + const size_t entry_size = (ordt_type == 0) ? 1 : 2; + if (ordt1_offset + entry_size * ordt_entries_count > indx_record->size + || ordt2_offset + 2 * ordt_entries_count > indx_record->size) { + ordt1_offset = 0; + ordt2_offset = 0; + ordt_entries_count = 0; + } + index_name_offset = mobi_buffer_get32(buf); /* 180: Index name offset */ + index_name_length = mobi_buffer_get32(buf); /* 184: Index name length */ + } + buf->maxlen = indx_record->size; + mobi_buffer_setpos(buf, header_length); + ret = mobi_parse_tagx(buf, tagx); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + return ret; + } + if (ordt_entries_count > 0) { + /* parse ORDT sections */ + ordt->offsets_count = ordt_entries_count; + ordt->type = ordt_type; + ordt->ordt1_pos = ordt1_offset; + ordt->ordt2_pos = ordt2_offset; + ret = mobi_parse_ordt(buf, ordt); + debug_print("ORDT: %u, %u, %u, %u\n", ordt_type, ordt_entries_count, ordt1_offset, ordt2_offset); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + return ret; + } + } + if (index_name_offset > 0 && index_name_length > 0) { + if (index_name_length <= header_length - index_name_offset && index_name_length < INDX_NAME_SIZEMAX) { + mobi_buffer_setpos(buf, index_name_offset); + char *name = malloc(index_name_length + 1); + if (name == NULL) { + debug_print("%s", "Memory allocation failed\n"); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_getstring(name, buf, index_name_length); + indx->orth_index_name = name; + debug_print("Orth index name: %s\n", name); + } + } + indx->encoding = encoding; + indx->type = type; + indx->entries_count = entries_count; + indx->total_entries_count = total_entries_count; + if (ligt_entries_count != 0 && !mobi_buffer_match_magic_offset(buf, LIGT_MAGIC, ligt_offset)) { + ligt_offset = 0; + ligt_entries_count = 0; + } + indx->ligt_offset = ligt_offset; + indx->ligt_entries_count = ligt_entries_count; + indx->ordt_offset = ordt_offset; + indx->cncx_records_count = cncx_records_count; + } else { + /* else parse IDXT entries offsets */ + if (idxt_offset == 0) { + debug_print("%s", "Missing IDXT offset\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + if (idxt_offset + 2 * entries_count + 4 > indx_record->size ) { + debug_print("IDXT entries beyond record end%s", "\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_setpos(buf, idxt_offset); + MOBIIdxt idxt; + uint32_t *offsets = malloc((entries_count + 1) * sizeof(uint32_t)); + if (offsets == NULL) { + mobi_buffer_free_null(buf); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + idxt.offsets = offsets; + ret = mobi_parse_idxt(buf, &idxt, entries_count); + if (ret != MOBI_SUCCESS) { + debug_print("%s", "IDXT parsing failed\n"); + mobi_buffer_free_null(buf); + free(offsets); + return ret; + } + /* parse entries */ + if (entries_count > 0) { + if (indx->entries == NULL) { + indx->entries = malloc(indx->total_entries_count * sizeof(MOBIIndexEntry)); + if (indx->entries == NULL) { + mobi_buffer_free_null(buf); + free(offsets); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + } + size_t i = 0; + while (i < entries_count) { + ret = mobi_parse_index_entry(indx, idxt, tagx, ordt, buf, i); + if (ret != MOBI_SUCCESS) { + indx->entries_count += i; + mobi_buffer_free_null(buf); + free(offsets); + return ret; + } + i++; + } + indx->entries_count += entries_count; + } + free(offsets); + } + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Parser of a set of index records + + @param[in] m MOBIData structure containing MOBI file metadata and data + @param[in,out] indx MOBIIndx structure to be filled with parsed entries + @param[in] indx_record_number Number of the first record of the set + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_index(const MOBIData *m, MOBIIndx *indx, const size_t indx_record_number) { + MOBI_RET ret; + /* tagx->tags array will be allocated in mobi_parse_tagx */ + MOBITagx *tagx = calloc(1, sizeof(MOBITagx)); + if (tagx == NULL) { + mobi_free_indx(indx); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + /* ordt->ordt1 and ordt.ordt2 arrays will be allocated in mobi_parse_ordt */ + MOBIOrdt *ordt = calloc(1, sizeof(MOBIOrdt)); + if (ordt == NULL) { + mobi_free_indx(indx); + mobi_free_tagx(tagx); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + /* parse first meta INDX record */ + MOBIPdbRecord *record = mobi_get_record_by_seqnumber(m, indx_record_number); + ret = mobi_parse_indx(record, indx, tagx, ordt); + if (ret != MOBI_SUCCESS) { + mobi_free_indx(indx); + mobi_free_tagx(tagx); + mobi_free_ordt(ordt); + return ret; + } + /* parse remaining INDX records for the index */ + size_t count = indx->entries_count; + indx->entries_count = 0; + while (count--) { + record = record->next; + ret = mobi_parse_indx(record, indx, tagx, ordt); + if (ret != MOBI_SUCCESS) { + mobi_free_indx(indx); + mobi_free_tagx(tagx); + mobi_free_ordt(ordt); + return ret; + } + } + if (indx->entries_count != indx->total_entries_count) { + debug_print("Entries count %zu != total entries count %zu\n", indx->entries_count, indx->total_entries_count); + mobi_free_indx(indx); + mobi_free_tagx(tagx); + mobi_free_ordt(ordt); + return MOBI_DATA_CORRUPT; + } + /* copy pointer to first cncx record if present and set info from first record */ + if (indx->cncx_records_count) { + indx->cncx_record = record->next; + } + mobi_free_tagx(tagx); + mobi_free_ordt(ordt); + return MOBI_SUCCESS; +} + +/** + @brief Get a value of tag[tagid][tagindex] for given index entry + + @param[in,out] tagvalue Will be set to a tag value + @param[in] entry Index entry to be search for the value + @param[in] tag_arr Array: tag_arr[0] = tagid, tag_arr[1] = tagindex + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_indxentry_tagvalue(uint32_t *tagvalue, const MOBIIndexEntry *entry, const unsigned tag_arr[]) { + if (entry == NULL) { + debug_print("%s", "INDX entry not initialized\n"); + return MOBI_INIT_FAILED; + } + size_t i = 0; + while (i < entry->tags_count) { + if (entry->tags[i].tagid == tag_arr[0]) { + if (entry->tags[i].tagvalues_count > tag_arr[1]) { + *tagvalue = entry->tags[i].tagvalues[tag_arr[1]]; + return MOBI_SUCCESS; + } + break; + } + i++; + } + //debug_print("tag[%i][%i] not found in entry: %s\n", tag_arr[0], tag_arr[1], entry->label); + return MOBI_DATA_CORRUPT; +} + +/** + @brief Get array of tagvalues of tag[tagid] for given index entry + + @param[in,out] tagarr Pointer to tagvalues array + @param[in] entry Index entry to be search for the value + @param[in] tagid Id of the tag + @return Size of the array (zero on failure) + */ +size_t mobi_get_indxentry_tagarray(uint32_t **tagarr, const MOBIIndexEntry *entry, const size_t tagid) { + if (entry == NULL) { + debug_print("%s", "INDX entry not initialized\n"); + return 0; + } + size_t i = 0; + while (i < entry->tags_count) { + if (entry->tags[i].tagid == tagid) { + *tagarr = entry->tags[i].tagvalues; + return entry->tags[i].tagvalues_count; + } + i++; + } + //debug_print("tag[%zu] not found in entry: %s\n", tagid, entry->label); + return 0; +} + +/** + @brief Get entry start offset for the orth entry + @param[in] entry MOBIIndexEntry structure + @return Start offset, MOBI_NOTSET on failure + */ +uint32_t mobi_get_orth_entry_offset(const MOBIIndexEntry *entry) { + + uint32_t entry_startpos; + MOBI_RET ret = mobi_get_indxentry_tagvalue(&entry_startpos, entry, INDX_TAG_ORTH_POSITION); + if (ret != MOBI_SUCCESS) { + return MOBI_NOTSET; + } + + return entry_startpos; +} + +/** + @brief Get text length for the orth entry + @param[in] entry MOBIIndexEntry structure + @return Text length, MOBI_NOTSET on failure + */ +uint32_t mobi_get_orth_entry_length(const MOBIIndexEntry *entry) { + + uint32_t entry_textlen; + MOBI_RET ret = mobi_get_indxentry_tagvalue(&entry_textlen, entry, INDX_TAG_ORTH_LENGTH); + if (ret != MOBI_SUCCESS) { + return MOBI_NOTSET; + } + + return entry_textlen; +} + +/** + @brief Check if given tagid is present in the index + + @param[in] indx Index MOBIIndx structure + @param[in] tagid Id of the tag + @return True on success, false otherwise + */ +bool mobi_indx_has_tag(const MOBIIndx *indx, const size_t tagid) { + if (indx) { + for (size_t i = 0; i < indx->entries_count; i++) { + MOBIIndexEntry entry = indx->entries[i]; + for(size_t j = 0; j < entry.tags_count; j++) { + if (entry.tags[j].tagid == tagid) { + return true; + } + } + } + } + return false; +} + +/** + @brief Get compiled index entry string + + Allocates memory for the string. Must be freed by caller. + + @param[in] cncx_record MOBIPdbRecord structure with cncx record + @param[in] cncx_offset Offset of string entry from the beginning of the record + @return Entry string or null if malloc failed + */ +char * mobi_get_cncx_string(const MOBIPdbRecord *cncx_record, const uint32_t cncx_offset) { + /* TODO: handle multiple cncx records */ + MOBIBuffer *buf = mobi_buffer_init_null(cncx_record->data, cncx_record->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return NULL; + } + mobi_buffer_setpos(buf, cncx_offset); + size_t len = 0; + const uint32_t string_length = mobi_buffer_get_varlen(buf, &len); + char *string = malloc(string_length + 1); + if (string) { + mobi_buffer_getstring(string, buf, string_length); + } + mobi_buffer_free_null(buf); + return string; +} + +/** + @brief Get compiled index entry string, converted to utf8 encoding + + Allocates memory for the string. Must be freed by caller. + + @param[in] cncx_record MOBIPdbRecord structure with cncx record + @param[in] cncx_offset Offset of string entry from the beginning of the record + @param[in] cncx_encoding Encoding + @return Entry string or null if malloc failed + */ +char * mobi_get_cncx_string_utf8(const MOBIPdbRecord *cncx_record, const uint32_t cncx_offset, MOBIEncoding cncx_encoding) { + char *string = mobi_get_cncx_string(cncx_record, cncx_offset); + if (string != NULL && cncx_encoding == MOBI_CP1252) { + size_t in_len = strlen(string); + size_t out_len = in_len * 3 + 1; + char *decoded = malloc(out_len); + if (decoded) { + mobi_cp1252_to_utf8(decoded, string, &out_len, in_len); + free(string); + string = strdup(decoded); + free(decoded); + } + } + return string; +} + +/** + @brief Get flat index entry string + + Allocates memory for the string. Must be freed by caller. + + @param[in] cncx_record MOBIPdbRecord structure with cncx record + @param[in] cncx_offset Offset of string entry from the beginning of the record + @param[in] length Length of the string to be extracted + @return Entry string + */ +char * mobi_get_cncx_string_flat(const MOBIPdbRecord *cncx_record, const uint32_t cncx_offset, const size_t length) { + /* TODO: handle multiple cncx records */ + MOBIBuffer *buf = mobi_buffer_init_null(cncx_record->data, cncx_record->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return NULL; + } + mobi_buffer_setpos(buf, cncx_offset); + char *string = malloc(length + 1); + if (string) { + mobi_buffer_getstring(string, buf, length); + } + mobi_buffer_free_null(buf); + return string; +} + +/** + @brief Decode compiled infl index entry + + Buffer decoded must be initialized with basic index entry. + Basic index entry will be transformed into inflected form, + based on compiled rule. + Min. size of input buffer (decoded) must be INDX_INFLBUF_SIZEMAX + 1 + + @param[in,out] decoded Decoded entry string + @param[in,out] decoded_size Decoded entry size + @param[in] rule Compiled rule + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decode_infl(unsigned char *decoded, int *decoded_size, const unsigned char *rule) { + int pos = *decoded_size; + char mod = 'i'; + char dir = '<'; + char olddir; + unsigned char c; + while ((c = *rule++)) { + if (c <= 4) { + mod = (c <= 2) ? 'i' : 'd'; /* insert, delete */ + olddir = dir; + dir = (c & 2) ? '<' : '>'; /* left, right */ + if (olddir != dir && olddir) { + pos = (c & 2) ? *decoded_size : 0; + } + } + else if (c > 10 && c < 20) { + if (dir == '>') { + pos = *decoded_size; + } + pos -= c - 10; + dir = 0; + } + else { + if (mod == 'i') { + const unsigned char *s = decoded + pos; + unsigned char *d = decoded + pos + 1; + const int l = *decoded_size - pos; + if (pos < 0 || l < 0 || d + l > decoded + INDX_INFLBUF_SIZEMAX) { + debug_print("Out of buffer in %s at pos: %i\n", decoded, pos); + return MOBI_DATA_CORRUPT; + } + memmove(d, s, (size_t) l); + decoded[pos] = c; + (*decoded_size)++; + if (dir == '>') { pos++; } + } else { + if (dir == '<') { pos--; } + const unsigned char *s = decoded + pos + 1; + unsigned char *d = decoded + pos; + const int l = *decoded_size - pos; + if (pos < 0 || l < 0 || s + l > decoded + INDX_INFLBUF_SIZEMAX) { + debug_print("Out of buffer in %s at pos: %i\n", decoded, pos); + return MOBI_DATA_CORRUPT; + } + if (decoded[pos] != c) { + debug_print("Character mismatch in %s at pos: %i (%c != %c)\n", decoded, pos, decoded[pos], c); + return MOBI_DATA_CORRUPT; + } + memmove(d, s, (size_t) l); + (*decoded_size)--; + } + } + } + return MOBI_SUCCESS; +} + +/** + @brief Get all matches for given string from trie structure + + Matches are made agains reversed string and all its substrings + + @param[in,out] infl_strings Array of returned strings + @param[in] root Root node of the tree + @param[in] string Index entry number + @return Number of returned strings + */ +size_t mobi_trie_get_inflgroups(char **infl_strings, MOBITrie * const root, const char *string) { + /* travers trie and get values for each substring */ + if (root == NULL) { + return 0; + } + size_t count = 0; + size_t length = strlen(string); + MOBITrie *node = root; + while (node && length > 0) { + char **values = NULL; + size_t values_count = 0; + node = mobi_trie_get_next(&values, &values_count, node, string[length - 1]); + length--; + for (size_t j = 0; j < values_count; j++) { + if (count == INDX_INFLSTRINGS_MAX) { + debug_print("Inflection strings array too small (%d)\n", INDX_INFLSTRINGS_MAX); + break; + } + char infl_string[INDX_LABEL_SIZEMAX + 1]; + const size_t suffix_length = strlen(values[j]); + if (length + suffix_length > INDX_LABEL_SIZEMAX) { + debug_print("Label too long (%zu + %zu)\n", length, suffix_length); + continue; + } + memcpy(infl_string, string, length); + memcpy(infl_string + length, values[j], suffix_length); + infl_string[length + suffix_length] = '\0'; + infl_strings[count++] = strdup(infl_string); + } + } + return count; +} + +/** + @brief Insert inversed inlection string for given entry into trie structure + + @param[in,out] root Root node of the tree, created if NULL + @param[in] indx MOBIIndx infl index records + @param[in] i Index entry number + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_trie_insert_infl(MOBITrie **root, const MOBIIndx *indx, size_t i) { + if (indx->cncx_record == NULL) { + return MOBI_DATA_CORRUPT; + } + MOBIIndexEntry e = indx->entries[i]; + char *inflected = e.label; + for (size_t j = 0; j < e.tags_count; j++) { + MOBIIndexTag t = e.tags[j]; + if (t.tagid == INDX_TAGARR_INFL_PARTS_V1) { + for (size_t k = 0; k + 1 < t.tagvalues_count; k += 2) { + uint32_t len = t.tagvalues[k]; + uint32_t offset = t.tagvalues[k + 1]; + char *base = mobi_get_cncx_string_flat(indx->cncx_record, offset, len); + if (base == NULL) { + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = mobi_trie_insert_reversed(root, base, inflected); + free(base); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + } + } + return MOBI_SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/index.h b/Charcoal/Charcoal/libmobi-public/src/index.h new file mode 100644 index 0000000..5491cac --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/index.h @@ -0,0 +1,128 @@ +/** @file index.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_index_h +#define mobi_index_h + +#include "config.h" +#include "structure.h" +#include "mobi.h" + +/** + @defgroup index_tag Predefined tag arrays: {tagid, tagindex} for mobi_get_indxentry_tagvalue() + @{ + */ +#define INDX_TAG_GUIDE_TITLE_CNCX (unsigned[]) {1, 0} /**< Guide title CNCX offset */ + +#define INDX_TAG_NCX_FILEPOS (unsigned[]) {1, 0} /**< NCX filepos offset */ +#define INDX_TAG_NCX_TEXT_CNCX (unsigned[]) {3, 0} /**< NCX text CNCX offset */ +#define INDX_TAG_NCX_LEVEL (unsigned[]) {4, 0} /**< NCX level */ +#define INDX_TAG_NCX_KIND_CNCX (unsigned[]) {5, 0} /**< NCX kind CNCX offset */ +#define INDX_TAG_NCX_POSFID (unsigned[]) {6, 0} /**< NCX pos:fid */ +#define INDX_TAG_NCX_POSOFF (unsigned[]) {6, 1} /**< NCX pos:off */ +#define INDX_TAG_NCX_PARENT (unsigned[]) {21, 0} /**< NCX parent */ +#define INDX_TAG_NCX_CHILD_START (unsigned[]) {22, 0} /**< NCX start child */ +#define INDX_TAG_NCX_CHILD_END (unsigned[]) {23, 0} /**< NCX last child */ + +#define INDX_TAG_SKEL_COUNT (unsigned[]) {1, 0} /**< Skel fragments count */ +#define INDX_TAG_SKEL_POSITION (unsigned[]) {6, 0} /**< Skel position */ +#define INDX_TAG_SKEL_LENGTH (unsigned[]) {6, 1} /**< Skel length */ + +#define INDX_TAG_FRAG_AID_CNCX (unsigned[]) {2, 0} /**< Frag aid CNCX offset */ +#define INDX_TAG_FRAG_FILE_NR (unsigned[]) {3, 0} /**< Frag file number */ +#define INDX_TAG_FRAG_SEQUENCE_NR (unsigned[]) {4, 0} /**< Frag sequence number */ +#define INDX_TAG_FRAG_POSITION (unsigned[]) {6, 0} /**< Frag position */ +#define INDX_TAG_FRAG_LENGTH (unsigned[]) {6, 1} /**< Frag length */ + +#define INDX_TAG_ORTH_POSITION (unsigned[]) {1, 0} /**< Orth entry start position */ +#define INDX_TAG_ORTH_LENGTH (unsigned[]) {2, 0} /**< Orth entry end position */ + +#define INDX_TAGARR_ORTH_INFL 42 /**< Inflection groups for orth entry */ +#define INDX_TAGARR_INFL_GROUPS 5 /**< Inflection groups in infl index */ +#define INDX_TAGARR_INFL_PARTS_V2 26 /**< Inflection particles in infl index */ + +#define INDX_TAGARR_INFL_PARTS_V1 7 /**< Inflection particles in old type infl index */ +/** @} */ + +#define INDX_LABEL_SIZEMAX 1000 /**< Max size of index label */ +#define INDX_INFLTAG_SIZEMAX 25000 /**< Max size of inflections tags per entry */ +#define INDX_INFLBUF_SIZEMAX 500 /**< Max size of index label */ +#define INDX_INFLSTRINGS_MAX 500 /**< Max number of inflected strings */ +#define ORDT_RECORD_MAXCNT 256 /* max entries count in old ordt */ +#define CNCX_RECORD_MAXCNT 0xf /* max entries count */ +#define INDX_RECORD_MAXCNT 10000 /* max index entries per record */ +#define INDX_TOTAL_MAXCNT ((size_t) INDX_RECORD_MAXCNT * 0xffff) /* max total index entries */ +#define INDX_NAME_SIZEMAX 0xff + +/** + @brief Maximum value of tag values in index entry (MOBIIndexTag) + */ +#define INDX_TAGVALUES_MAX 100 + +/** + @brief Tag entries in TAGX section (for internal INDX parsing) + */ +typedef struct { + uint8_t tag; /**< Tag */ + uint8_t values_count; /**< Number of values */ + uint8_t bitmask; /**< Bitmask */ + uint8_t control_byte; /**< EOF control byte */ +} TAGXTags; + +/** + @brief Parsed TAGX section (for internal INDX parsing) + + TAGX tags hold metadata of index entries. + It is present in the first index record. + */ +typedef struct { + TAGXTags *tags; /**< Array of tag entries */ + size_t tags_count; /**< Number of tag entries */ + size_t control_byte_count; /**< Number of control bytes */ +} MOBITagx; + +/** + @brief Parsed IDXT section (for internal INDX parsing) + + IDXT section holds offsets to index entries + */ +typedef struct { + uint32_t *offsets; /**< Offsets to index entries */ + size_t offsets_count; /**< Offsets count */ +} MOBIIdxt; + +/** + @brief Parsed ORDT sections (for internal INDX parsing) + + ORDT sections hold data for decoding index labels. + It is mapping of encoded chars to unicode. + */ +typedef struct { + uint8_t *ordt1; /**< ORDT1 offsets */ + uint16_t *ordt2; /**< ORDT2 offsets */ + size_t type; /**< Type (0: 16, 1: 8 bit offsets) */ + size_t ordt1_pos; /**< Offset of ORDT1 data */ + size_t ordt2_pos; /**< Offset of ORDT2 data */ + size_t offsets_count; /**< Offsets count */ +} MOBIOrdt; + +MOBI_RET mobi_parse_index(const MOBIData *m, MOBIIndx *indx, const size_t indx_record_number); +MOBI_RET mobi_parse_indx(const MOBIPdbRecord *indx_record, MOBIIndx *indx, MOBITagx *tagx, MOBIOrdt *ordt); +MOBI_RET mobi_get_indxentry_tagvalue(uint32_t *tagvalue, const MOBIIndexEntry *entry, const unsigned tag_arr[]); +size_t mobi_get_indxentry_tagarray(uint32_t **tagarr, const MOBIIndexEntry *entry, const size_t tagid); +bool mobi_indx_has_tag(const MOBIIndx *indx, const size_t tagid); +char * mobi_get_cncx_string(const MOBIPdbRecord *cncx_record, const uint32_t cncx_offset); +char * mobi_get_cncx_string_utf8(const MOBIPdbRecord *cncx_record, const uint32_t cncx_offset, MOBIEncoding cncx_encoding); +char * mobi_get_cncx_string_flat(const MOBIPdbRecord *cncx_record, const uint32_t cncx_offset, const size_t length); +MOBI_RET mobi_decode_infl(unsigned char *decoded, int *decoded_size, const unsigned char *rule); +MOBI_RET mobi_trie_insert_infl(MOBITrie **root, const MOBIIndx *indx, size_t i); +size_t mobi_trie_get_inflgroups(char **infl_strings, MOBITrie * const root, const char *string); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/memory.c b/Charcoal/Charcoal/libmobi-public/src/memory.c new file mode 100644 index 0000000..2956dbf --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/memory.c @@ -0,0 +1,444 @@ +/** @file memory.c + * @brief Functions for initializing and releasing structures and data containers + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include "memory.h" +#include "debug.h" +#include "util.h" + +/** + @brief Initializer for MOBIData structure + + It allocates memory for structure. + Memory should be freed with mobi_free(). + + @return MOBIData on success, NULL otherwise + */ +MOBIData * mobi_init(void) { + MOBIData *m = NULL; + m = calloc(1, sizeof(MOBIData)); + if (m == NULL) { return NULL; } + m->use_kf8 = true; + m->kf8_boundary_offset = MOBI_NOTSET; + m->drm_key = NULL; + m->ph = NULL; + m->rh = NULL; + m->mh = NULL; + m->eh = NULL; + m->rec = NULL; + m->next = NULL; + m->internals = NULL; + return m; +} + +/** + @brief Free MOBIMobiHeader structure + + @param[in] mh MOBIMobiHeader structure + */ +void mobi_free_mh(MOBIMobiHeader *mh) { + if (mh == NULL) { + return; + } + free(mh->header_length); + free(mh->mobi_type); + free(mh->text_encoding); + free(mh->uid); + free(mh->version); + free(mh->orth_index); + free(mh->infl_index); + free(mh->names_index); + free(mh->keys_index); + free(mh->extra0_index); + free(mh->extra1_index); + free(mh->extra2_index); + free(mh->extra3_index); + free(mh->extra4_index); + free(mh->extra5_index); + free(mh->non_text_index); + free(mh->full_name_offset); + free(mh->full_name_length); + free(mh->locale); + free(mh->dict_input_lang); + free(mh->dict_output_lang); + free(mh->min_version); + free(mh->image_index); + free(mh->huff_rec_index); + free(mh->huff_rec_count); + free(mh->datp_rec_index); + free(mh->datp_rec_count); + free(mh->exth_flags); + free(mh->unknown6); + free(mh->drm_offset); + free(mh->drm_count); + free(mh->drm_size); + free(mh->drm_flags); + free(mh->fdst_index); + free(mh->first_text_index); + free(mh->last_text_index); + free(mh->fdst_section_count); + //free(mh->unknown9); + free(mh->fcis_index); + free(mh->fcis_count); + free(mh->flis_index); + free(mh->flis_count); + free(mh->unknown10); + free(mh->unknown11); + free(mh->srcs_index); + free(mh->srcs_count); + free(mh->unknown12); + free(mh->unknown13); + free(mh->extra_flags); + free(mh->ncx_index); + free(mh->fragment_index); + free(mh->skeleton_index); + free(mh->unknown14); + free(mh->unknown15); + free(mh->datp_index); + free(mh->guide_index); + free(mh->unknown16); + free(mh->unknown17); + free(mh->unknown18); + free(mh->unknown19); + free(mh->unknown20); + free(mh->full_name); + free(mh); + mh = NULL; +} + +/** + @brief Free all MOBIPdbRecord structures and its respective data attached to MOBIData structure + + Each MOBIPdbRecord structure holds metadata and data for each pdb record + + @param[in,out] m MOBIData structure + */ +void mobi_free_rec(MOBIData *m) { + MOBIPdbRecord *curr, *tmp; + curr = m->rec; + while (curr != NULL) { + tmp = curr; + curr = curr->next; + free(tmp->data); + free(tmp); + tmp = NULL; + } + m->rec = NULL; +} + +/** + @brief Free all MOBIExthHeader structures and its respective data attached to MOBIData structure + + Each MOBIExthHeader structure holds metadata and data for each EXTH record + + @param[in,out] m MOBIData structure + */ +void mobi_free_eh(MOBIData *m) { + MOBIExthHeader *curr, *tmp; + curr = m->eh; + while (curr != NULL) { + tmp = curr; + curr = curr->next; + free(tmp->data); + free(tmp); + tmp = NULL; + } + m->eh = NULL; +} + +/** + @brief Free MOBIData structure for currenly unused hybrid part and all its children + + @param[in] m MOBIData structure + */ +void mobi_free_next(MOBIData *m) { + if (m && m->next) { + mobi_free_mh(m->next->mh); + mobi_free_eh(m->next); + free(m->next->rh); + free(m->next); + m->next = NULL; + } +} + +/** + @brief Free MOBIData structure and all its children + + @param[in] m MOBIData structure + */ +void mobi_free(MOBIData *m) { + if (m == NULL) { + return; + } + mobi_free_mh(m->mh); + mobi_free_eh(m); + mobi_free_rec(m); + free(m->ph); + free(m->rh); + mobi_free_next(m); + mobi_free_internals(m); + free(m); + m = NULL; +} + +/** + @brief Initialize and return MOBIHuffCdic structure. + + MOBIHuffCdic structure holds parsed data from HUFF, CDIC records. + It is used for huffman decompression. + Initialized structure is a child of MOBIData structure. + It must be freed with mobi_free_huffcdic(). + + @return MOBIHuffCdic on success, NULL otherwise + */ +MOBIHuffCdic * mobi_init_huffcdic(void) { + MOBIHuffCdic *huffcdic = calloc(1, sizeof(MOBIHuffCdic)); + if (huffcdic == NULL) { + debug_print("%s", "Memory allocation for huffcdic structure failed\n"); + return NULL; + } + return huffcdic; +} + +/** + @brief Free MOBIHuffCdic structure and all its children + + @param[in] huffcdic MOBIData structure + */ +void mobi_free_huffcdic(MOBIHuffCdic *huffcdic) { + if (huffcdic == NULL) { + return; + } + free(huffcdic->symbol_offsets); + free(huffcdic->symbols); + free(huffcdic); + huffcdic = NULL; +} + +/** + @brief Initialize and return MOBIRawml structure. + + MOBIRawml structure holds parsed text record metadata. + It is used in the process of parsing rawml text data. + It must be freed with mobi_free_rawml(). + + @param[in] m Initialized MOBIData structure + @return MOBIRawml on success, NULL otherwise + */ +MOBIRawml * mobi_init_rawml(const MOBIData *m) { + MOBIRawml *rawml = malloc(sizeof(MOBIRawml)); + if (rawml == NULL) { + debug_print("%s", "Memory allocation failed for rawml structure\n"); + return NULL; + } + rawml->version = mobi_get_fileversion(m); + rawml->fdst = NULL; + rawml->skel = NULL; + rawml->frag = NULL; + rawml->guide = NULL; + rawml->ncx = NULL; + rawml->orth = NULL; + rawml->infl = NULL; + rawml->flow = NULL; + rawml->markup = NULL; + rawml->resources = NULL; + return rawml; +} + +/** + @brief Free MOBIFdst structure and all its children + + @param[in] fdst MOBIFdst structure + */ +void mobi_free_fdst(MOBIFdst *fdst) { + if (fdst == NULL) { + return; + } + if (fdst->fdst_section_count > 0) { + free(fdst->fdst_section_starts); + free(fdst->fdst_section_ends); + } + free(fdst); + fdst = NULL; +} + +/** + @brief Initialize and return MOBIIndx structure. + + MOBIIndx structure holds INDX index record entries. + Must be freed with mobi_free_indx() + + @return MOBIIndx on success, NULL otherwise + */ +MOBIIndx * mobi_init_indx(void) { + MOBIIndx *indx = calloc(1, sizeof(MOBIIndx)); + if (indx == NULL) { + debug_print("%s", "Memory allocation failed for indx structure\n"); + return NULL; + } + indx->entries = NULL; + indx->cncx_record = NULL; + indx->orth_index_name = NULL; + return indx; +} + +/** + @brief Free index entries data and all its children + + @param[in] indx MOBIIndx structure that holds indx->entries + */ +void mobi_free_index_entries(MOBIIndx *indx) { + if (indx == NULL || indx->entries == NULL) { + return; + } + size_t i = 0; + while (i < indx->entries_count) { + free(indx->entries[i].label); + if (indx->entries[i].tags != NULL) { + size_t j = 0; + while (j < indx->entries[i].tags_count) { + free(indx->entries[i].tags[j++].tagvalues); + } + free(indx->entries[i].tags); + } + i++; + } + free(indx->entries); + indx->entries = NULL; +} + +/** + @brief Free MOBIIndx structure and all its children + + @param[in] indx MOBIIndx structure that holds indx->entries + */ +void mobi_free_indx(MOBIIndx *indx) { + if (indx == NULL) { + return; + } + mobi_free_index_entries(indx); + if (indx->orth_index_name) { + free(indx->orth_index_name); + } + free(indx); + indx = NULL; +} + +/** + @brief Free MOBITagx structure and all its children + + @param[in] tagx MOBITagx structure + */ +void mobi_free_tagx(MOBITagx *tagx) { + if (tagx == NULL) { + return; + } + free(tagx->tags); + free(tagx); + tagx = NULL; +} + +/** + @brief Free MOBIOrdt structure and all its children + + @param[in] ordt MOBIOrdt structure + */ +void mobi_free_ordt(MOBIOrdt *ordt) { + if (ordt == NULL) { + return; + } + free(ordt->ordt1); + free(ordt->ordt2); + free(ordt); + ordt = NULL; +} + +/** + @brief Free MOBIPart structure + + Pointer to data may point to memory area also used by record->data. + So we need a flag to leave the memory allocated, while freeing MOBIPart structure + + @param[in] part MOBIPart structure + @param[in] free_data Flag, if set - a pointer to part->data is also released, otherwise not released + */ +void mobi_free_part(MOBIPart *part, int free_data) { + MOBIPart *curr, *tmp; + curr = part; + while (curr != NULL) { + tmp = curr; + curr = curr->next; + if (free_data) { free(tmp->data); } + free(tmp); + } + part = NULL; +} + +/** + @brief Free MOBIPart structure for opf and ncx data + + @param[in] part MOBIPart structure + */ +void mobi_free_opf_data(MOBIPart *part) { + while (part != NULL) { + if (part->type == T_NCX || part->type == T_OPF) { + free(part->data); + } + part = part->next; + } +} + +/** + @brief Free MOBIPart structure for decoded font data + + @param[in] part MOBIPart structure + */ +void mobi_free_font_data(MOBIPart *part) { + while (part != NULL) { + if (part->type == T_OTF || part->type == T_TTF) { + free(part->data); + } + part = part->next; + } +} + +/** + @brief Free MOBIRawml structure allocated by mobi_init_rawml() + + Pointer to data may point to memory area also used by record->data. + So we need a flag to leave the memory allocated, while freeing MOBIPart structure + + @param[in] rawml MOBIRawml structure + */ +void mobi_free_rawml(MOBIRawml *rawml) { + if (rawml == NULL) { + return; + } + mobi_free_fdst(rawml->fdst); + mobi_free_indx(rawml->skel); + mobi_free_indx(rawml->frag); + mobi_free_indx(rawml->guide); + mobi_free_indx(rawml->ncx); + mobi_free_indx(rawml->orth); + mobi_free_indx(rawml->infl); + mobi_free_part(rawml->flow, true); + mobi_free_part(rawml->markup,true); + /* do not free resources data, these are links to records data */ + /* only free opf and ncx data */ + mobi_free_opf_data(rawml->resources); + /* and free decoded fonts data */ + mobi_free_font_data(rawml->resources); + mobi_free_part(rawml->resources, false); + free(rawml); + rawml = NULL; +} + + diff --git a/Charcoal/Charcoal/libmobi-public/src/memory.h b/Charcoal/Charcoal/libmobi-public/src/memory.h new file mode 100644 index 0000000..5aa2909 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/memory.h @@ -0,0 +1,33 @@ +/** @file memory.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_memory_h +#define libmobi_memory_h + +#include "config.h" +#include "index.h" +#include "compression.h" +#include "mobi.h" + +void mobi_free_mh(MOBIMobiHeader *mh); +void mobi_free_rec(MOBIData *m); +void mobi_free_eh(MOBIData *m); +void mobi_free_next(MOBIData *m); + +MOBIHuffCdic * mobi_init_huffcdic(void); +void mobi_free_huffcdic(MOBIHuffCdic *huffcdic); + +MOBIIndx * mobi_init_indx(void); +void mobi_free_indx(MOBIIndx *indx); +void mobi_free_tagx(MOBITagx *tagx); +void mobi_free_ordt(MOBIOrdt *ordt); +void mobi_free_index_entries(MOBIIndx *indx); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/meta.c b/Charcoal/Charcoal/libmobi-public/src/meta.c new file mode 100644 index 0000000..309e73f --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/meta.c @@ -0,0 +1,864 @@ +/** @file meta.c + * @brief Functions for metadata manipulation + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#define _GNU_SOURCE 1 +#ifndef __USE_BSD +#define __USE_BSD /* for strdup on linux/glibc */ +#endif + +#include +#include +#include +#include "meta.h" +#include "util.h" + +/** + @brief Get document metadata from exth string + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @param[in] exth_tag MOBIExthTag + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_exthstring(const MOBIData *m, const MOBIExthTag exth_tag) { + char *string = NULL; + + MOBIExthHeader *exth; + MOBIExthHeader *start = NULL; + while ((exth = mobi_next_exthrecord_by_tag(m, exth_tag, &start))) { + char *exth_string = mobi_decode_exthstring(m, exth->data, exth->size); + if (string == NULL) { + string = exth_string; + } else if (exth_string) { + const char *separator = "; "; + size_t new_length = strlen(string) + strlen(exth_string) + strlen(separator) + 1; + char *new = malloc(new_length); + if (new == NULL) { + free(string); + free(exth_string); + return NULL; + } + strcpy(new, string); + strcat(new, separator); + strcat(new, exth_string); + free(string); + free(exth_string); + string = new; + } + if (start == NULL) { + break; + } + } + return string; +} + +/** + @brief Get document title metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_title(const MOBIData *m) { + if (m == NULL) { + return NULL; + } + char *title = mobi_meta_get_exthstring(m, EXTH_UPDATEDTITLE); + if (title) { + return title; + } + char fullname[MOBI_TITLE_SIZEMAX + 1]; + MOBI_RET ret = mobi_get_fullname(m, fullname, MOBI_TITLE_SIZEMAX); + if (ret == MOBI_SUCCESS) { + title = strdup(fullname); + } else if (m->ph) { + title = strdup(m->ph->name); + } + return title; +} + +/** + @brief Add document title metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] title String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_title(MOBIData *m, const char *title) { + if (title == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(title), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_UPDATEDTITLE, (uint32_t) size, title); +} + +/** + @brief Delete all title metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_title(MOBIData *m) { + if (mobi_exists_mobiheader(m) && m->mh->full_name) { + m->mh->full_name[0] = '\0'; + } + if (mobi_is_hybrid(m) && mobi_exists_mobiheader(m->next) && m->next->mh->full_name) { + m->next->mh->full_name[0] = '\0'; + } + return mobi_delete_exthrecord_by_tag(m, EXTH_UPDATEDTITLE); +} + +/** + @brief Set document title metadata + + Replaces all title metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] title String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_title(MOBIData *m, const char *title) { + if (title == NULL) { + return MOBI_PARAM_ERR; + } + /* set title in mobi header */ + MOBI_RET ret = mobi_set_fullname(m, title); + if (ret != MOBI_SUCCESS) { + return ret; + } + /* set title in palm header */ + ret = mobi_set_pdbname(m, title); + if (ret != MOBI_SUCCESS) { + return ret; + } + /* set title in exth header */ + ret = mobi_delete_exthrecord_by_tag(m, EXTH_UPDATEDTITLE); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_title(m, title); + } + return ret; +} + +/** + @brief Get document author metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_author(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_AUTHOR); +} + +/** + @brief Add document author metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] author String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_author(MOBIData *m, const char *author) { + if (author == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(author), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_AUTHOR, (uint32_t) size, author); +} + +/** + @brief Delete all author metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_author(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_AUTHOR); +} + +/** + @brief Set document author metadata + + Replaces all author metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] author String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_author(MOBIData *m, const char *author) { + if (author == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_author(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_author(m, author); + } + return ret; +} + +/** + @brief Get document subject metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_subject(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_SUBJECT); +} + +/** + @brief Add document subject metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] subject String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_subject(MOBIData *m, const char *subject) { + if (subject == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(subject), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_SUBJECT, (uint32_t) size, subject); +} + +/** + @brief Delete all subject metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_subject(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_SUBJECT); +} + +/** + @brief Set document subject metadata + + Replaces all subject metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] subject String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_subject(MOBIData *m, const char *subject) { + if (subject == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_subject(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_subject(m, subject); + } + return ret; +} + +/** + @brief Get document publisher metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_publisher(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_PUBLISHER); +} + +/** + @brief Add document publisher metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] publisher String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_publisher(MOBIData *m, const char *publisher) { + if (publisher == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(publisher), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_PUBLISHER, (uint32_t) size, publisher); +} + +/** + @brief Delete all publisher metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_publisher(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_PUBLISHER); +} + +/** + @brief Set document publisher metadata + + Replaces all publisher metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] publisher String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_publisher(MOBIData *m, const char *publisher) { + if (publisher == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_publisher(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_publisher(m, publisher); + } + return ret; +} + +/** + @brief Get document publishing date metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_publishdate(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_PUBLISHINGDATE); +} + +/** + @brief Add document publishdate metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] publishdate String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_publishdate(MOBIData *m, const char *publishdate) { + if (publishdate == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(publishdate), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_PUBLISHINGDATE, (uint32_t) size, publishdate); +} + +/** + @brief Delete all publishdate metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_publishdate(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_PUBLISHINGDATE); +} + +/** + @brief Set document publishdate metadata + + Replaces all publishdate metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] publishdate String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_publishdate(MOBIData *m, const char *publishdate) { + if (publishdate == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_publishdate(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_publishdate(m, publishdate); + } + return ret; +} + +/** + @brief Get document description metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_description(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_DESCRIPTION); +} + +/** + @brief Add document description metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] description String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_description(MOBIData *m, const char *description) { + if (description == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(description), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_DESCRIPTION, (uint32_t) size, description); +} + +/** + @brief Delete all description metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_description(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_DESCRIPTION); +} + +/** + @brief Set document description metadata + + Replaces all description metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] description String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_description(MOBIData *m, const char *description) { + if (description == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_description(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_description(m, description); + } + return ret; +} + +/** + @brief Get document imprint metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_imprint(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_IMPRINT); +} + +/** + @brief Add document imprint metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] imprint String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_imprint(MOBIData *m, const char *imprint) { + if (imprint == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(imprint), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_IMPRINT, (uint32_t) size, imprint); +} + +/** + @brief Delete all imprint metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_imprint(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_IMPRINT); +} + +/** + @brief Set document imprint metadata + + Replaces all imprint metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] imprint String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_imprint(MOBIData *m, const char *imprint) { + if (imprint == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_imprint(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_imprint(m, imprint); + } + return ret; +} + +/** + @brief Get document contributor metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_contributor(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_CONTRIBUTOR); +} + +/** + @brief Add document contributor metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] contributor String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_contributor(MOBIData *m, const char *contributor) { + if (contributor == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(contributor), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_CONTRIBUTOR, (uint32_t) size, contributor); +} + +/** + @brief Delete all contributor metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_contributor(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_CONTRIBUTOR); +} + +/** + @brief Set document contributor metadata + + Replaces all contributor metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] contributor String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_contributor(MOBIData *m, const char *contributor) { + if (contributor == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_contributor(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_contributor(m, contributor); + } + return ret; +} + +/** + @brief Get document review metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_review(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_REVIEW); +} + +/** + @brief Add document review metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] review String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_review(MOBIData *m, const char *review) { + if (review == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(review), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_REVIEW, (uint32_t) size, review); +} + +/** + @brief Delete all review metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_review(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_REVIEW); +} + +/** + @brief Set document review metadata + + Replaces all review metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] review String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_review(MOBIData *m, const char *review) { + if (review == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_review(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_review(m, review); + } + return ret; +} + +/** + @brief Get document copyright metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_copyright(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_RIGHTS); +} + +/** + @brief Add document copyright metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] copyright String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_copyright(MOBIData *m, const char *copyright) { + if (copyright == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(copyright), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_RIGHTS, (uint32_t) size, copyright); +} + +/** + @brief Delete all copyright metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_copyright(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_RIGHTS); +} + +/** + @brief Set document copyright metadata + + Replaces all copyright metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] copyright String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_copyright(MOBIData *m, const char *copyright) { + if (copyright == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_copyright(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_copyright(m, copyright); + } + return ret; +} + +/** + @brief Get document ISBN metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_isbn(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_ISBN); +} + +/** + @brief Add document isbn metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] isbn String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_isbn(MOBIData *m, const char *isbn) { + if (isbn == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(isbn), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_ISBN, (uint32_t) size, isbn); +} + +/** + @brief Delete all isbn metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_isbn(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_ISBN); +} + +/** + @brief Set document isbn metadata + + Replaces all isbn metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] isbn String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_isbn(MOBIData *m, const char *isbn) { + if (isbn == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_isbn(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_isbn(m, isbn); + } + return ret; +} + +/** + @brief Get document ASIN metadata + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_asin(const MOBIData *m) { + return mobi_meta_get_exthstring(m, EXTH_ASIN); +} + +/** + @brief Add document asin metadata + + @param[in,out] m MOBIData structure with loaded data + @param[in] asin String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_asin(MOBIData *m, const char *asin) { + if (asin == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(asin), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_ASIN, (uint32_t) size, asin); +} + +/** + @brief Delete all asin metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_asin(MOBIData *m) { + return mobi_delete_exthrecord_by_tag(m, EXTH_ASIN); +} + +/** + @brief Set document asin metadata + + Replaces all asin metadata with new string + + @param[in,out] m MOBIData structure with loaded data + @param[in] asin String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_asin(MOBIData *m, const char *asin) { + if (asin == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_asin(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_asin(m, asin); + } + return ret; +} + +/** + @brief Get document language code metadata + + Locale strings are based on IANA language-subtag registry with some custom Mobipocket modifications. + See mobi_locale array. + + Returned string must be deallocated by caller + + @param[in] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +char * mobi_meta_get_language(const MOBIData *m) { + if (m == NULL) { + return NULL; + } + char *lang = mobi_meta_get_exthstring(m, EXTH_LANGUAGE); + if(lang == NULL && m->mh && m->mh->locale && *m->mh->locale) { + const char *locale_string = mobi_get_locale_string(*m->mh->locale); + if (locale_string) { + lang = strdup(locale_string); + } + } + return lang; +} + +/** + @brief Add document language code metadata + + Locale strings are based on IANA language-subtag registry with some custom Mobipocket modifications. + See mobi_locale array. + + @param[in,out] m MOBIData structure with loaded data + @param[in] language String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_add_language(MOBIData *m, const char *language) { + if (language == NULL) { + return MOBI_PARAM_ERR; + } + size_t size = min(strlen(language), UINT32_MAX); + return mobi_add_exthrecord(m, EXTH_LANGUAGE, (uint32_t) size, language); +} + +/** + @brief Delete all language code metadata + + @param[in,out] m MOBIData structure with loaded data + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_delete_language(MOBIData *m) { + if(mobi_exists_mobiheader(m) && m->mh->locale) { + *m->mh->locale = 0; + } + if(mobi_is_hybrid(m) && mobi_exists_mobiheader(m->next) && m->next->mh->locale) { + *m->next->mh->locale = 0; + } + return mobi_delete_exthrecord_by_tag(m, EXTH_LANGUAGE); +} + +/** + @brief Set document language code metadata + + Replaces all language metadata with new string + Locale strings are based on IANA language-subtag registry with some custom Mobipocket modifications. + See mobi_locale array. + + @param[in,out] m MOBIData structure with loaded data + @param[in] language String value + @return Pointer to null terminated string, NULL on failure + */ +MOBI_RET mobi_meta_set_language(MOBIData *m, const char *language) { + if (language == NULL) { + return MOBI_PARAM_ERR; + } + MOBI_RET ret = mobi_meta_delete_language(m); + if (ret == MOBI_SUCCESS) { + ret = mobi_meta_add_language(m, language); + } + if(mobi_exists_mobiheader(m) && m->mh->locale) { + *m->mh->locale = (uint32_t) mobi_get_locale_number(language); + } + if(mobi_is_hybrid(m) && mobi_exists_mobiheader(m->next) && m->next->mh->locale) { + *m->next->mh->locale = (uint32_t) mobi_get_locale_number(language); + } + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/meta.h b/Charcoal/Charcoal/libmobi-public/src/meta.h new file mode 100644 index 0000000..0d6814f --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/meta.h @@ -0,0 +1,17 @@ +/** @file meta.h + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_meta_h +#define libmobi_meta_h + +#include "config.h" +#include "mobi.h" + +#endif /* libmobi_meta_h */ diff --git a/Charcoal/Charcoal/libmobi-public/src/miniz.c b/Charcoal/Charcoal/libmobi-public/src/miniz.c new file mode 100644 index 0000000..dfe1a43 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/miniz.c @@ -0,0 +1,5164 @@ +/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Change History + 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!): + - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug + would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place() + (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag). + - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size + - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries. + Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice). + - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes + - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed + - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6. + - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti + - Merged MZ_FORCEINLINE fix from hdeanclark + - Fix include before config #ifdef, thanks emil.brink + - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can + set it to 1 for real-time compression). + - Merged in some compiler fixes from paulharris's github repro. + - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3. + - Added example6.c, which dumps an image of the mandelbrot set to a PNG file. + - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. + - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled + - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. + - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). + - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. + - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. + - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. + - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) + - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a + - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). + - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. + - Refactored the compression code for better readability and maintainability. + - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). + */ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +#include + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or +// get/set file times, and the C run-time funcs that get/set times won't be called. +// The current downside is the times written to your archives will be from 1979. +//#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux +#define MINIZ_NO_TIME +#endif + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + // ------------------- zlib-style API Definitions. + + // For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! + typedef unsigned long mz_ulong; + + // mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. + void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) + // mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. + mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) + // mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. + mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + + // Compression strategies. + enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; + + // Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + + // Heap allocation callbacks. + // Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. + typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); + typedef void (*mz_free_func)(void *opaque, void *address); + typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 + + // Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). + enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + + // Return status codes. MZ_PARAM_ERROR is non-standard. + enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + + // Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. + enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + + // Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + + struct mz_internal_state; + + // Compression/decompression stream struct. + typedef struct mz_stream_s { + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used + } mz_stream; + + typedef mz_stream *mz_streamp; + + // Returns the version string of miniz.c. + const char *mz_version(void); + + // mz_deflateInit() initializes a compressor with default options: + // Parameters: + // pStream must point to an initialized mz_stream struct. + // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. + // level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. + // (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) + // Return values: + // MZ_OK on success. + // MZ_STREAM_ERROR if the stream is bogus. + // MZ_PARAM_ERROR if the input parameters are bogus. + // MZ_MEM_ERROR on out of memory. + int mz_deflateInit(mz_streamp pStream, int level); + + // mz_deflateInit2() is like mz_deflate(), except with more control: + // Additional parameters: + // method must be MZ_DEFLATED + // window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) + // mem_level must be between [1, 9] (it's checked but ignored by miniz.c) + int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + + // Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). + int mz_deflateReset(mz_streamp pStream); + + // mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. + // Parameters: + // pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. + // flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. + // Return values: + // MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). + // MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. + // MZ_STREAM_ERROR if the stream is bogus. + // MZ_PARAM_ERROR if one of the parameters is invalid. + // MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) + int mz_deflate(mz_streamp pStream, int flush); + + // mz_deflateEnd() deinitializes a compressor: + // Return values: + // MZ_OK on success. + // MZ_STREAM_ERROR if the stream is bogus. + int mz_deflateEnd(mz_streamp pStream); + + // mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. + mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + + // Single-call compression functions mz_compress() and mz_compress2(): + // Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. + int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + + // mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). + mz_ulong mz_compressBound(mz_ulong source_len); + + // Initializes a decompressor. + int mz_inflateInit(mz_streamp pStream); + + // mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: + // window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). + int mz_inflateInit2(mz_streamp pStream, int window_bits); + + // Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. + // Parameters: + // pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. + // flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. + // On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). + // MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. + // Return values: + // MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. + // MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. + // MZ_STREAM_ERROR if the stream is bogus. + // MZ_DATA_ERROR if the deflate stream is invalid. + // MZ_PARAM_ERROR if one of the parameters is invalid. + // MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again + // with more input data, or with more room in the output buffer (except when using single call decompression, described above). + int mz_inflate(mz_streamp pStream, int flush); + + // Deinitializes a decompressor. + int mz_inflateEnd(mz_streamp pStream); + + // Single-call decompression. + // Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. + int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + + // Returns a string description of the specified error code, or NULL if the error code is invalid. + const char *mz_error(int err); + + // Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. + // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + typedef unsigned char Byte; + typedef unsigned int uInt; + typedef mz_ulong uLong; + typedef Byte Bytef; + typedef uInt uIntf; + typedef char charf; + typedef int intf; + typedef void *voidpf; + typedef uLong uLongf; + typedef void *voidp; + typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + + // ------------------- Types and macros + + typedef unsigned char mz_uint8; + typedef signed short mz_int16; + typedef unsigned short mz_uint16; + typedef unsigned int mz_uint32; + typedef unsigned int mz_uint; + typedef long long mz_int64; + typedef unsigned long long mz_uint64; + typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + + // An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + + // ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + + enum { + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 + }; + + typedef struct { + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + } mz_zip_archive_file_stat; + + typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); + typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); + + struct mz_zip_internal_state_tag; + typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + + typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 + } mz_zip_mode; + + typedef struct mz_zip_archive_tag { + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + + } mz_zip_archive; + + typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 + } mz_zip_flags; + + // ZIP archive reading + + // Inits a ZIP archive reader. + // These functions read and validate the archive's central directory. + mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); + mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO + mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +#endif + + // Returns the total number of files in the archive. + mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + + // Returns detailed information about an archive file entry. + mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + + // Determines if an archive file entry is a directory entry. + mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + + // Retrieves the filename of an archive file entry. + // Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. + mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + + // Attempts to locates a file in the archive's central directory. + // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH + // Returns -1 if the file cannot be found. + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + // Extracts a archive file to a memory buffer using no memory allocation. + mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + + // Extracts a archive file to a memory buffer. + mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); + mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + + // Extracts a archive file to a dynamically allocated heap buffer. + void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); + void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + + // Extracts a archive file using a callback function to output the file's data. + mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO + // Extracts a archive file to a disk file and sets its last accessed and modified times. + // This function only extracts files, not archive directory records. + mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); + mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); +#endif + + // Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. + mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + + // ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + + // Inits a ZIP archive writer. + mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); + mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO + mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +#endif + + // Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. + // For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. + // For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). + // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. + // Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before + // the archive is finalized the file's central directory will be hosed. + mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); + + // Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. + // To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. + // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. + mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO + // Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. + // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. + mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +#endif + + // Adds a file to an archive by fully cloning the data from another archive. + // This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. + mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); + + // Finalizes the archive by writing the central directory records followed by the end of central directory record. + // After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). + // An archive must be manually finalized by calling this function for it to be valid. + mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); + + // Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. + // Note for the archive to be valid, it must have been finalized before ending. + mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + + // Misc. high-level helper functions: + + // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. + // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + // Reads a single file from an archive into a heap block. + // Returns NULL on failure. + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + + // ------------------- Low-level Decompression API Definitions + + // Decompression flags used by tinfl_decompress(). + // TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. + // TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. + // TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). + // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. + enum { + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 + }; + + // High level decompression functions: + // tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). + // On entry: + // pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. + // On return: + // Function returns a pointer to the decompressed data, or NULL on failure. + // *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. + // The caller must call mz_free() on the returned block when it's no longer needed. + void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + + // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. + // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) + size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + + // tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. + // Returns 1 on success or 0 on failure. + typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + struct tinfl_decompressor_tag; + typedef struct tinfl_decompressor_tag tinfl_decompressor; + + // Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + + // Return status. + typedef enum { + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 + } tinfl_status; + + // Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + + // Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. + // This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. + tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + + // Internal/private bits follow. + enum { + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS + }; + + typedef struct { + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; + } tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + + struct tinfl_decompressor_tag { + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; + }; + + // ------------------- Low-level Compression API Definitions + + // Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + + // tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): + // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). + enum { + TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF + }; + + // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. + // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). + // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. + // TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). + // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) + // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. + // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. + // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. + // The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). + enum { + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 + }; + + // High level compression functions: + // tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). + // On entry: + // pSrc_buf, src_buf_len: Pointer and size of source block to compress. + // flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. + // On return: + // Function returns a pointer to the compressed data, or NULL on failure. + // *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. + // The caller must free() the returned block when it's no longer needed. + void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + + // tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. + // Returns 0 on failure. + size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + + // Compresses an image to a compressed PNG file in memory. + // On entry: + // pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. + // The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. + // level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL + // If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). + // On return: + // Function returns a pointer to the compressed data, or NULL on failure. + // *pLen_out will be set to the size of the PNG image file. + // The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. + void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); + void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + + // Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. + typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + + // tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. + mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; + + // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY + enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#else + enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#endif + + // The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. + typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, + } tdefl_status; + + // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums + typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 + } tdefl_flush; + + // tdefl's compression state structure. + typedef struct { + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; + } tdefl_compressor; + + // Initializes the compressor. + // There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. + // pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. + // If pBut_buf_func is NULL the user should always call the tdefl_compress() API. + // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) + tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + + // Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. + tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + + // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. + // tdefl_compress_buffer() always consumes the entire input buffer. + tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + + tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); + mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + + // Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS + // Create tdefl_compress() flags given zlib-style compression parameters. + // level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) + // window_bits may be -15 (raw deflate) or 15 (zlib) + // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED + mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +// Ignore strict-aliasing warning on MinGW gcc +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif +// Ignore conversion warnings on clang +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#endif + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#include +#define NDEBUG +#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + // ------------------- zlib-style API's + + mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) { + return MZ_ADLER32_INIT; + } + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) { + s1 += *ptr++, s2 += s1; + } + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; + } + + // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ + mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) { + return MZ_CRC32_INIT; + } + crcu32 = ~crcu32; + while (buf_len--) { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; + } + + void mz_free(void *p) { + MZ_FREE(p); + } + +#ifndef MINIZ_NO_ZLIB_APIS + + static void *def_alloc_func(void *opaque, size_t items, size_t size) { + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); + } + static void def_free_func(void *opaque, void *address) { + (void)opaque, (void)address; + MZ_FREE(address); + } + static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); + } + + const char *mz_version(void) { + return MZ_VERSION; + } + + int mz_deflateInit(mz_streamp pStream, int level) { + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); + } + + int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + if (!pStream) { + return MZ_STREAM_ERROR; + } + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) { + return MZ_PARAM_ERROR; + } + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) { + pStream->zalloc = def_alloc_func; + } + if (!pStream->zfree) { + pStream->zfree = def_free_func; + } + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) { + return MZ_MEM_ERROR; + } + pStream->state = (struct mz_internal_state *)pComp; + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + return MZ_OK; + } + + int mz_deflateReset(mz_streamp pStream) { + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) { + return MZ_STREAM_ERROR; + } + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; + } + + int mz_deflate(mz_streamp pStream, int flush) { + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) { + return MZ_STREAM_ERROR; + } + if (!pStream->avail_out) { + return MZ_BUF_ERROR; + } + if (flush == MZ_PARTIAL_FLUSH) { + flush = MZ_SYNC_FLUSH; + } + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) { + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + } + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for ( ; ; ) { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + if (defl_status < 0) { + mz_status = MZ_STREAM_ERROR; + break; + } else if (defl_status == TDEFL_STATUS_DONE) { + mz_status = MZ_STREAM_END; + break; + } else if (!pStream->avail_out) { + break; + } else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) { + break; + } + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; + } + + int mz_deflateEnd(mz_streamp pStream) { + if (!pStream) { + return MZ_STREAM_ERROR; + } + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; + } + + mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); + } + + int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) { + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) { + return MZ_PARAM_ERROR; + } + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32) * pDest_len; + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) { + return status; + } + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); + } + + int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); + } + + mz_ulong mz_compressBound(mz_ulong source_len) { + return mz_deflateBound(NULL, source_len); + } + + typedef struct { + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; + } inflate_state; + + int mz_inflateInit2(mz_streamp pStream, int window_bits) { + inflate_state *pDecomp; + if (!pStream) { + return MZ_STREAM_ERROR; + } + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) { + return MZ_PARAM_ERROR; + } + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) { + pStream->zalloc = def_alloc_func; + } + if (!pStream->zfree) { + pStream->zfree = def_free_func; + } + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) { + return MZ_MEM_ERROR; + } + pStream->state = (struct mz_internal_state *)pDecomp; + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + return MZ_OK; + } + + int mz_inflateInit(mz_streamp pStream) { + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); + } + + int mz_inflate(mz_streamp pStream, int flush) { + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + if ((!pStream) || (!pStream->state)) { + return MZ_STREAM_ERROR; + } + if (flush == MZ_PARTIAL_FLUSH) { + flush = MZ_SYNC_FLUSH; + } + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) { + return MZ_STREAM_ERROR; + } + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) { + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + } + orig_avail_in = pStream->avail_in; + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) { + return MZ_DATA_ERROR; + } + if (pState->m_has_flushed && (flush != MZ_FINISH)) { + return MZ_STREAM_ERROR; + } + pState->m_has_flushed |= (flush == MZ_FINISH); + if ((flush == MZ_FINISH) && (first_call)) { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + if (status < 0) { + return MZ_DATA_ERROR; + } else if (status != TINFL_STATUS_DONE) { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) { + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + } + if (pState->m_dict_avail) { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + for ( ; ; ) { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pState->m_dict_avail = (mz_uint)out_bytes; + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + if (status < 0) { + return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + } else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) { + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + } else if (flush == MZ_FINISH) { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) { + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + } + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) { + return MZ_BUF_ERROR; + } + } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) { + break; + } + } + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + int mz_inflateEnd(mz_streamp pStream) { + if (!pStream) { + return MZ_STREAM_ERROR; + } + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; + } + + int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) { + return MZ_PARAM_ERROR; + } + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32) * pDest_len; + status = mz_inflateInit(&stream); + if (status != MZ_OK) { + return status; + } + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + return mz_inflateEnd(&stream); + } + + const char *mz_error(int err) { + static struct { + int m_err; + const char *m_pDesc; + } s_error_descs[] = { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, + { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) { + return s_error_descs[i].m_pDesc; + } + return NULL; + } + +#endif //MINIZ_NO_ZLIB_APIS + + // ------------------- Low-level Decompression (completely independent from all compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + + // TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never + // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ +if (pIn_buf_cur >= pIn_buf_end) { \ +for ( ; ; ) { \ +if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ +TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ +if (pIn_buf_cur < pIn_buf_end) { \ +c = *pIn_buf_cur++; \ +break; \ +} \ +} else { \ +c = 0; \ +break; \ +} \ +} \ +} else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + + // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. + // It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a + // Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the + // bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ +do { \ +temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ +if (temp >= 0) { \ +code_len = temp >> 9; \ +if ((code_len) && (num_bits >= code_len)) \ +break; \ +} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ +code_len = TINFL_FAST_LOOKUP_BITS; \ +do { \ +temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ +} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ +} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ +} while (num_bits < 15); + + // TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read + // beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully + // decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. + // The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ +int temp; mz_uint code_len, c; \ +if (num_bits < 15) { \ +if ((pIn_buf_end - pIn_buf_cur) < 2) { \ +TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ +} else { \ +bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ +} \ +} \ +if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ +code_len = temp >> 9, temp &= 511; \ +else { \ +code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ +} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + + tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) { + static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t) - 1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + } + if (counter) { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + do { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + if (num_bits) { + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + } else { + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } else { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } else if (r->m_type == 3) { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } else { + if (r->m_type == 1) { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) { + *p++ = 8; + } + for ( ; i <= 255; ++i) { + *p++ = 9; + } + for ( ; i <= 279; ++i) { + *p++ = 7; + } + for ( ; i <= 287; ++i) { + *p++ = 8; + } + } else { + for (counter = 0; counter < 3; counter++) { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) { + total_syms[pTable->m_code_size[i]]++; + } + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; + if (!code_size) { + continue; + } + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) { + rev_code = (rev_code << 1) | (cur_code & 1); + } + if (code_size <= TINFL_FAST_LOOKUP_BITS) { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } else { + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) { + mz_uint8 *pSrc; + for ( ; ; ) { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) { + break; + } + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } else { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) { + code_len = sym2 >> 9; + } else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) { + break; + } +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) { + code_len = sym2 >> 9; + } else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) { + break; + } + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { + while (counter--) { + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) { + if (counter) { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) { + pOut_buf_cur[1] = pSrc[1]; + } + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) { + pOut_buf_cur[1] = pSrc[1]; + } + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_SKIP_BITS(32, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + mz_uint s; + if (num_bits) { + TINFL_GET_BITS(41, s, 8); + } else { + TINFL_GET_BYTE(42, s); + } + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + common_exit: + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf; + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) { + s1 += *ptr++, s2 += s1; + } + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) { + status = TINFL_STATUS_ADLER32_MISMATCH; + } + } + return status; + } + + // Higher level helper functions. + void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) { + break; + } + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) { + new_out_buf_capacity = 128; + } + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; + } + + size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; + } + + int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) { + return TINFL_STATUS_FAILED; + } + tinfl_init(&decomp); + for ( ; ; ) { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) { + break; + } + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; + } + + // ------------------- Low-level Compression (independent from all decompression API's) + + // Purposely making these tables static for faster init and thread safety. + static const mz_uint16 s_tdefl_len_sym[256] = { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + + static const mz_uint8 s_tdefl_len_extra[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + + static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + + static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + + static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + + static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + + // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. + typedef struct { + mz_uint16 m_key, m_sym_index; + } tdefl_sym_freq; + static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) { + total_passes--; + } + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) { + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + } + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; + } + + // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. + static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { + int root, leaf, next, avbl, used, dpth; + if (n == 0) { + return; + } else if (n == 1) { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) { + if (leaf >= n || A[root].m_key < A[leaf].m_key) { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } else { + A[next].m_key = A[leaf++].m_key; + } + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } else { + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) { + A[next].m_key = A[A[next].m_key].m_key + 1; + } + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) { + while (root >= 0 && (int)A[root].m_key == dpth) { + used++; + root--; + } + while (avbl > used) { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } + } + + // Limits canonical Huffman code table's max code size. + enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; + static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) { + return; + } + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) { + pNum_codes[max_code_size] += pNum_codes[i]; + } + for (i = max_code_size; i > 0; i--) { + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + } + while (total != (1UL << max_code_size)) { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } + } + + static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) { + for (i = 0; i < table_len; i++) { + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + } else { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + for (i = 0; i < num_used_syms; i++) { + num_codes[pSyms[i].m_key]++; + } + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) { + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + } + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) { + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + } + for (i = 0; i < table_len; i++) { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) { + continue; + } + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) { + rev_code = (rev_code << 1) | (code & 1); + } + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } + } + +#define TDEFL_PUT_BITS(b, l) do { \ +mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ +d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ +while (d->m_bits_in >= 8) { \ +if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ +*d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ +d->m_bit_buffer >>= 8; \ +d->m_bits_in -= 8; \ +} \ +} MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ +if (rle_repeat_count < 3) { \ +d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ +while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ +} else { \ +d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ +} rle_repeat_count = 0; } } + +#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ +if (rle_z_count < 3) { \ +d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ +} else if (rle_z_count <= 10) { \ +d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ +} else { \ +d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ +} rle_z_count = 0; } } + + static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + + static void tdefl_start_dynamic_block(tdefl_compressor *d) { + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + d->m_huff_count[0][256] = 1; + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) { + break; + } + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) { + break; + } + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } else if (++rle_repeat_count == 6) { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { + TDEFL_RLE_PREV_CODE_SIZE(); + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + TDEFL_PUT_BITS(2, 2); + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) { + break; + } + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) { + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + } + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) { + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } + } + } + + static void tdefl_start_static_block(tdefl_compressor *d) { + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + for (i = 0; i <= 143; ++i) { + *p++ = 8; + } + for ( ; i <= 255; ++i) { + *p++ = 9; + } + for ( ; i <= 279; ++i) { + *p++ = 7; + } + for ( ; i <= 287; ++i) { + *p++ = 8; + } + memset(d->m_huff_code_sizes[1], 5, 32); + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + TDEFL_PUT_BITS(1, 2); + } + + static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; +#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { + if (flags == 1) { + flags = *pLZ_codes++ | 0x100; + } + if (flags & 1) { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + if (pOutput_buf >= d->m_pOutput_buf_end) { + return MZ_FALSE; + } + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } +#undef TDEFL_PUT_BITS_FAST + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + while (bits_in) { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + return (d->m_pOutput_buf < d->m_pOutput_buf_end); + } +#else + static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { + if (flags == 1) { + flags = *pLZ_codes++ | 0x100; + } + if (flags & 1) { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + if (match_dist < 512) { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } else { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + return (d->m_pOutput_buf < d->m_pOutput_buf_end); + } +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + + static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { + if (static_block) { + tdefl_start_static_block(d); + } else { + tdefl_start_dynamic_block(d); + } + return tdefl_compress_lz_codes(d); + } + + static int tdefl_flush_block(tdefl_compressor *d, int flush) { + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + if (!use_raw_block) { + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + } + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + if (flush) { + if (flush == TDEFL_FINISH) { + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } else { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { + if (d->m_pPut_buf_func) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) { + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + } else if (pOutput_buf_start == d->m_output_buf) { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } else { + d->m_out_buf_ofs += n; + } + } + return d->m_output_flush_remaining; + } + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) + static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) { + return; + } + for ( ; ; ) { + for ( ; ; ) { + if (--num_probes_left == 0) { + return; + } +#define TDEFL_PROBE \ +next_probe_pos = d->m_next[probe_pos]; \ +if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ +probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ +if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) { + break; + } + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) { + continue; + } + p = s; + probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + if (!probe_len) { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); + break; + } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) { + break; + } + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } + } +#else + static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) { + return; + } + for ( ; ; ) { + for ( ; ; ) { + if (--num_probes_left == 0) { + return; + } +#define TDEFL_PROBE \ +next_probe_pos = d->m_next[probe_pos]; \ +if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ +probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ +if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) { + break; + } + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) { + break; + } + if (probe_len > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) { + return; + } + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } + } +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + static mz_bool tdefl_compress_fast(tdefl_compressor *d) { + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + while (num_bytes_to_process) { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) { + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + } + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) { + break; + } + while (lookahead_size >= 4) { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) { + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + } + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } else { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + cur_match_dist--; + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + if ((cur_match_len - TDEFL_MIN_MATCH_LEN) < sizeof(s_tdefl_len_sym) / sizeof(s_tdefl_len_sym[0])) { + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + } else { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) { + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + while (lookahead_size) { + mz_uint8 lit = d->m_dict[cur_pos]; + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) { + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; + } +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + + static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; + } + + static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { + mz_uint32 s0, s1; + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + d->m_total_lz_bytes += match_len; + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + if (match_len >= TDEFL_MIN_MATCH_LEN) { + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + + static mz_bool tdefl_compress_normal(tdefl_compressor *d) { + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) { + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + } + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } else { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) { + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + } + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { + break; + } + // Simple lazy/greedy parsing state machine. + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) { + if (d->m_dict[cur_pos + cur_match_len] != c) { + break; + } + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) { + cur_match_len = 0; + } else { + cur_match_dist = 1; + } + } + } else { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) { + if (cur_match_len > d->m_saved_match_len) { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } else { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } else if (!cur_match_dist) { + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + } else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ( (d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) { + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + } + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; + } + + static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { + if (d->m_pIn_buf_size) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + if (d->m_pOut_buf_size) { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; + } + + tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { + if (!d) { + if (pIn_buf_size) { + *pIn_buf_size = 0; + } + if (pOut_buf_size) { + *pOut_buf_size = 0; + } + return TDEFL_STATUS_BAD_PARAM; + } + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) { + if (pIn_buf_size) { + *pIn_buf_size = 0; + } + if (pOut_buf_size) { + *pOut_buf_size = 0; + } + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + if ((d->m_output_flush_remaining) || (d->m_finished)) { + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { + if (!tdefl_compress_fast(d)) { + return d->m_prev_return_status; + } + } else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) { + return d->m_prev_return_status; + } + } + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) { + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + } + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { + if (tdefl_flush_block(d, flush) < 0) { + return d->m_prev_return_status; + } + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + } + + tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); + } + + tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) { + MZ_CLEAR_OBJ(d->m_hash); + } + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; + } + + tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { + return d->m_prev_return_status; + } + + mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { + return d->m_adler32; + } + + mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) { + return MZ_FALSE; + } + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) { + return MZ_FALSE; + } + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; + } + + typedef struct { + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; + } tdefl_output_buffer; + + static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) { + return MZ_FALSE; + } + do { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) { + return MZ_FALSE; + } + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; + } + + void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) { + return MZ_FALSE; + } else { + *pOut_len = 0; + } + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) { + return NULL; + } + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; + } + + size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) { + return 0; + } + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) { + return 0; + } + return out_buf.m_size; + } + +#ifndef MINIZ_NO_ZLIB_APIS + static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + + // level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). + mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) { + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + } + if (!level) { + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + } else if (strategy == MZ_FILTERED) { + comp_flags |= TDEFL_FILTER_MATCHES; + } else if (strategy == MZ_HUFFMAN_ONLY) { + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + } else if (strategy == MZ_FIXED) { + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + } else if (strategy == MZ_RLE) { + comp_flags |= TDEFL_RLE_MATCHES; + } + return comp_flags; + } +#endif //MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) +#endif + + // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + // This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. + void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) { + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. + static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) { + return NULL; + } + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { + MZ_FREE(pComp); + return NULL; + } + // write dummy header + for (z = 41; z; --z) { + tdefl_output_buffer_putter(&z, 1, &out_buf); + } + // compress image data + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + // write real header + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; + mz_uint8 pnghdr[41] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0, 0, (mz_uint8)(w >> 8), (mz_uint8)w, 0, 0, (mz_uint8)(h >> 8), (mz_uint8)h, 8, chans[num_chans], 0, 0, 0, 0, 0, 0, 0, + (mz_uint8)(*pLen_out >> 24), (mz_uint8)(*pLen_out >> 16), (mz_uint8)(*pLen_out >> 8), (mz_uint8) *pLen_out, 0x49, 0x44, 0x41, 0x54 + }; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) { + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + } + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) { + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + } + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; + } + void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); + } + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + + // ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) + static FILE *mz_fopen(const char *pFilename, const char *pMode) { + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; + } + static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) { + return NULL; + } + return pFile; + } +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#else +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + + // Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. + enum { + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + }; + + typedef struct { + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; + } mz_zip_array; + + struct mz_zip_internal_state_tag { + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; + }; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] + + static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); + } + + static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) { + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) { + return MZ_TRUE; + } + if (growing) { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) { + new_capacity *= 2; + } + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) { + return MZ_FALSE; + } + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; + } + + static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) { + if (new_capacity > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) { + return MZ_FALSE; + } + } + return MZ_TRUE; + } + + static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) { + if (new_size > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) { + return MZ_FALSE; + } + } + pArray->m_size = new_size; + return MZ_TRUE; + } + + static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) { + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); + } + + static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) { + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) { + return MZ_FALSE; + } + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; + } + +#ifndef MINIZ_NO_TIME + static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); + } + + static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); + } +#endif + +#ifndef MINIZ_NO_STDIO + static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { +#ifdef MINIZ_NO_TIME + (void)pFilename; + *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; + // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) { + return MZ_FALSE; + } + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; + } + +#ifndef MINIZ_NO_TIME + static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) { + struct utimbuf t; + t.actime = access_time; + t.modtime = modified_time; + return !utime(pFilename, &t); + } +#endif // #ifndef MINIZ_NO_TIME +#endif // #ifndef MINIZ_NO_STDIO + + static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) { + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) { + return MZ_FALSE; + } + if (!pZip->m_pAlloc) { + pZip->m_pAlloc = def_alloc_func; + } + if (!pZip->m_pFree) { + pZip->m_pFree = def_free_func; + } + if (!pZip->m_pRealloc) { + pZip->m_pRealloc = def_realloc_func; + } + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) { + return MZ_FALSE; + } + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; + } + + static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) { + break; + } + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); + } + +#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END + + // Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) + static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) { + int child, root = start; + for ( ; ; ) { + if ((child = (root << 1) + 1) >= size) { + break; + } + child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) { + break; + } + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + start--; + } + end = size - 1; + while (end > 0) { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for ( ; ; ) { + if ((child = (root << 1) + 1) >= end) { + break; + } + child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) { + break; + } + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } + } + + static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) { + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + // Find the end of central directory record by scanning the file from the end towards the beginning. + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for ( ; ; ) { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) { + return MZ_FALSE; + } + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) { + break; + } + if (i >= 0) { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) { + return MZ_FALSE; + } + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) { + return MZ_FALSE; + } + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) { + return MZ_FALSE; + } + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) { + return MZ_FALSE; + } + pZip->m_central_directory_file_ofs = cdir_ofs; + if (pZip->m_total_files) { + mz_uint i, n; + // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) { + return MZ_FALSE; + } + if (sort_central_dir) { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) { + return MZ_FALSE; + } + } + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) { + return MZ_FALSE; + } + // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) { + return MZ_FALSE; + } + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + if (sort_central_dir) { + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + } + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) { + return MZ_FALSE; + } + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) { + return MZ_FALSE; + } + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) { + return MZ_FALSE; + } + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) { + return MZ_FALSE; + } + n -= total_header_size; + p += total_header_size; + } + } + if (sort_central_dir) { + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + } + return MZ_TRUE; + } + + mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) { + if ((!pZip) || (!pZip->m_pRead)) { + return MZ_FALSE; + } + if (!mz_zip_reader_init_internal(pZip, flags)) { + return MZ_FALSE; + } + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; + } + + static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; + } + + mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) { + if (!mz_zip_reader_init_internal(pZip, flags)) { + return MZ_FALSE; + } + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; + } + +#ifndef MINIZ_NO_STDIO + static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) { + return 0; + } + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); + } + + mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) { + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) { + return MZ_FALSE; + } + if (MZ_FSEEK64(pFile, 0, SEEK_END)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; + } +#endif // #ifndef MINIZ_NO_STDIO + + mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { + return pZip ? pZip->m_total_files : 0; + } + + static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { + return NULL; + } + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + } + + mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) { + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { + return MZ_FALSE; + } + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); + } + + mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) { + mz_uint filename_len, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { + return MZ_FALSE; + } + // First see if the filename ends with a '/' character. + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') { + return MZ_TRUE; + } + } + // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. + // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. + // FIXME: Remove this check? Is it necessary - we already check the filename. + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & 0x10) != 0) { + return MZ_TRUE; + } + return MZ_FALSE; + } + + mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) { + return MZ_FALSE; + } + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); + pStat->m_comment[n] = '\0'; + return MZ_TRUE; + } + + mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { + if (filename_buf_size) { + pFilename[0] = '\0'; + } + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; + } + + static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) { + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) { + return 0 == memcmp(pA, pB, len); + } + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) { + return MZ_FALSE; + } + return MZ_TRUE; + } + + static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) { + break; + } + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); + } + + static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) { + int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) { + return file_index; + } else if (comp < 0) { + l = m + 1; + } else { + h = m - 1; + } + } + return -1; + } + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) { + mz_uint file_index; + size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { + return -1; + } + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) { + return mz_zip_reader_locate_file_binary_search(pZip, pName); + } + name_len = strlen(pName); + if (name_len > 0xFFFF) { + return -1; + } + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > 0xFFFF) { + return -1; + } + for (file_index = 0; file_index < pZip->m_total_files; file_index++) { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) { + continue; + } + if (comment_len) { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) { + continue; + } + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { + int ofs = filename_len - 1; + do { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) { + break; + } + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) { + return file_index; + } + } + return -1; + } + + mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + if ((buf_size) && (!pBuf)) { + return MZ_FALSE; + } + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) { + return MZ_FALSE; + } + // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) { + return MZ_TRUE; + } + // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) { + return MZ_TRUE; + } + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) { + return MZ_FALSE; + } + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) { + return MZ_FALSE; + } + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) { + return MZ_FALSE; + } + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) { + return MZ_FALSE; + } + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) { + return MZ_FALSE; + } + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) { + return MZ_FALSE; + } + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + // Decompress the file either directly from memory or from a file input buffer. + tinfl_init(&inflator); + if (pZip->m_pState->m_pMem) { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else if (pUser_read_buf) { + // Use a user provided read buffer. + if (!user_read_buf_size) { + return MZ_FALSE; + } + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } else { + // Temporarily allocate a read buffer. + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) { + return MZ_FALSE; + } + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + do { + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + if (status == TINFL_STATUS_DONE) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) { + status = TINFL_STATUS_FAILED; + } + } + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + return status == TINFL_STATUS_DONE; + } + + mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) { + return MZ_FALSE; + } + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); + } + + mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); + } + + mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); + } + + void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) { + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + if (pSize) { + *pSize = 0; + } + if (!p) { + return NULL; + } + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) { + return NULL; + } + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + if (pSize) { + *pSize = (size_t)alloc_size; + } + return pBuf; + } + + void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) { + if (pSize) { + *pSize = 0; + } + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); + } + + mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) { + return MZ_FALSE; + } + // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) { + return MZ_TRUE; + } + // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) { + return MZ_TRUE; + } + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) { + return MZ_FALSE; + } + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) { + return MZ_FALSE; + } + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) { + return MZ_FALSE; + } + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) { + return MZ_FALSE; + } + // Decompress the file either directly from memory or from a file input buffer. + if (pZip->m_pState->m_pMem) { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else { + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) { + return MZ_FALSE; + } + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) { + status = TINFL_STATUS_FAILED; + } else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); + } + //cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + //comp_remaining = 0; + } else { + while (comp_remaining) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + } + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } else { + tinfl_decompressor inflator; + tinfl_init(&inflator); + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { + status = TINFL_STATUS_FAILED; + } else { + do { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + if (out_buf_size) { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) { + status = TINFL_STATUS_FAILED; + } + } + if (!pZip->m_pState->m_pMem) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + if (pWrite_buf) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + } + return status == TINFL_STATUS_DONE; + } + + mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) { + return MZ_FALSE; + } + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); + } + +#ifndef MINIZ_NO_STDIO + static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) { + (void)ofs; + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); + } + + mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) { + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) { + return MZ_FALSE; + } + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) { + return MZ_FALSE; + } + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) { + return MZ_FALSE; + } +#ifndef MINIZ_NO_TIME + if (status) { + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); + } +#endif + return status; + } +#endif // #ifndef MINIZ_NO_STDIO + + mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { + return MZ_FALSE; + } + if (pZip->m_pState) { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return MZ_TRUE; + } + +#ifndef MINIZ_NO_STDIO + mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) { + return MZ_FALSE; + } + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); + } +#endif + + // ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + + static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + } + static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); + } +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + + mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) { + return MZ_FALSE; + } + if (pZip->m_file_offset_alignment) { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) { + return MZ_FALSE; + } + } + if (!pZip->m_pAlloc) { + pZip->m_pAlloc = def_alloc_func; + } + if (!pZip->m_pFree) { + pZip->m_pFree = def_free_func; + } + if (!pZip->m_pRealloc) { + pZip->m_pRealloc = def_realloc_func; + } + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) { + return MZ_FALSE; + } + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; + } + + static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + while (new_capacity < new_size) { + new_capacity *= 2; + } + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) { + return 0; + } + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; + } + + mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) { + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) { + return MZ_FALSE; + } + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; + } + +#ifndef MINIZ_NO_STDIO + static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) { + return 0; + } + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); + } + + mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) { + MZ_FILE *pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) { + return MZ_FALSE; + } + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) { + mz_uint64 cur_ofs = 0; + char buf[4096]; + MZ_CLEAR_OBJ(buf); + do { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; + } +#endif // #ifndef MINIZ_NO_STDIO + + mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { + return MZ_FALSE; + } + // No sense in trying to write to an archive that's already at the support max size + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) { + return MZ_FALSE; + } + pState = pZip->m_pState; + if (pState->m_pFile) { +#ifdef MINIZ_NO_STDIO + pFilename; + return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) { + return MZ_FALSE; + } + if (!pFilename) { + return MZ_FALSE; + } + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } else if (pState->m_pMem) { + // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) { + return MZ_FALSE; + } + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the user has specified a write function too. + else if (!pZip->m_pWrite) { + return MZ_FALSE; + } + // Start writing new files at the archive's current central directory location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + return MZ_TRUE; + } + + mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); + } + + typedef struct { + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; + } mz_zip_writer_add_state; + + static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) { + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) { + return MZ_FALSE; + } + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; + } + + static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; + } + + static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; + } + + static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) { + return MZ_FALSE; + } + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) { + return MZ_FALSE; + } + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + return MZ_TRUE; + } + + static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { + // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. + if (*pArchive_name == '/') { + return MZ_FALSE; + } + while (*pArchive_name) { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) { + return MZ_FALSE; + } + pArchive_name++; + } + return MZ_TRUE; + } + + static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { + mz_uint32 n; + if (!pZip->m_file_offset_alignment) { + return 0; + } + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); + } + + static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) { + return MZ_FALSE; + } + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; + } + + mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { + if (!pZip) { + return MZ_FALSE; + } + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + if ((int)level_and_flags < 0) { + level_and_flags = MZ_DEFAULT_LEVEL; + } + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) { + return MZ_FALSE; + } + pState = pZip->m_pState; + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) { + return MZ_FALSE; + } + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) { + return MZ_FALSE; + } + if (!mz_zip_writer_validate_archive_name(pArchive_name)) { + return MZ_FALSE; + } +#ifndef MINIZ_NO_TIME + { + time_t cur_time; + time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) { + return MZ_FALSE; + } + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) { + return MZ_FALSE; + } + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) { + return MZ_FALSE; + } + } + // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) { + return MZ_FALSE; + } + if ((!store_data_uncompressed) && (buf_size)) { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) { + return MZ_FALSE; + } + } + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + if (store_data_uncompressed) { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) { + method = MZ_DEFLATED; + } + } else if (buf_size) { + mz_zip_writer_add_state state; + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + method = MZ_DEFLATED; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) { + return MZ_FALSE; + } + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) { + return MZ_FALSE; + } + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) { + return MZ_FALSE; + } + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) { + return MZ_FALSE; + } + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + return MZ_TRUE; + } + +#ifndef MINIZ_NO_STDIO + mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { + if (!pZip) { + return MZ_FALSE; + } + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE *pSrc_file = NULL; + if ((int)level_and_flags < 0) { + level_and_flags = MZ_DEFAULT_LEVEL; + } + level = level_and_flags & 0xF; + if ((!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) { + return MZ_FALSE; + } + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) { + return MZ_FALSE; + } + if (!mz_zip_writer_validate_archive_name(pArchive_name)) { + return MZ_FALSE; + } + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) { + return MZ_FALSE; + } + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) { + return MZ_FALSE; + } + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) { + return MZ_FALSE; + } + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) { + return MZ_FALSE; + } + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + if (uncomp_size > 0xFFFFFFFF) { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) { + level = 0; + } + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + if (uncomp_size) { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (!level) { + while (uncomp_remaining) { + mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } else { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + for ( ; ; ) { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) { + break; + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) { + result = MZ_TRUE; + break; + } else if (status != TDEFL_STATUS_OKAY) { + break; + } + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + if (!result) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + method = MZ_DEFLATED; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + MZ_FCLOSE(pSrc_file); + pSrc_file = NULL; + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) { + return MZ_FALSE; + } + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) { + return MZ_FALSE; + } + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) { + return MZ_FALSE; + } + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) { + return MZ_FALSE; + } + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + return MZ_TRUE; + } +#endif // #ifndef MINIZ_NO_STDIO + + mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) { + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { + return MZ_FALSE; + } + if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) { + return MZ_FALSE; + } + pState = pZip->m_pState; + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) { + return MZ_FALSE; + } + cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) { + return MZ_FALSE; + } + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) { + return MZ_FALSE; + } + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { + return MZ_FALSE; + } + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) { + return MZ_FALSE; + } + while (comp_bytes_remaining) { + n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + comp_bytes_remaining -= n; + } + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + //cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) { + return MZ_FALSE; + } + orig_central_dir_size = pState->m_central_dir.m_size; + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) { + return MZ_FALSE; + } + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + if (pState->m_central_dir.m_size > 0xFFFFFFFF) { + return MZ_FALSE; + } + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + return MZ_TRUE; + } + + mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { + return MZ_FALSE; + } + pState = pZip->m_pState; + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) { + return MZ_FALSE; + } + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) { + return MZ_FALSE; + } + pZip->m_archive_size += central_dir_size; + } + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) { + return MZ_FALSE; + } +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) { + return MZ_FALSE; + } +#endif // #ifndef MINIZ_NO_STDIO + pZip->m_archive_size += sizeof(hdr); + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; + } + + mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) { + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) { + return MZ_FALSE; + } + if (pZip->m_pWrite != mz_zip_heap_write_func) { + return MZ_FALSE; + } + if (!mz_zip_writer_finalize_archive(pZip)) { + return MZ_FALSE; + } + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; + } + + mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) { + return MZ_FALSE; + } + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; + } + +#ifndef MINIZ_NO_STDIO + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) { + level_and_flags = MZ_DEFAULT_LEVEL; + } + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) { + return MZ_FALSE; + } + if (!mz_zip_writer_validate_archive_name(pArchive_name)) { + return MZ_FALSE; + } + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) { + return MZ_FALSE; + } + created_new_archive = MZ_TRUE; + } else { + // Append to an existing archive. + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + return MZ_FALSE; + } + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) { + status = MZ_FALSE; + } + if (!mz_zip_writer_end(&zip_archive)) { + status = MZ_FALSE; + } + if ((!status) && (created_new_archive)) { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; + } + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + if (pSize) { + *pSize = 0; + } + if ((!pZip_filename) || (!pArchive_name)) { + return NULL; + } + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + return NULL; + } + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) { + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + } + mz_zip_reader_end(&zip_archive); + return p; + } + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + + +// Ignore strict-aliasing warning on MinGW gcc +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +// Ignore conversion warnings on clang +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to + */ diff --git a/Charcoal/Charcoal/libmobi-public/src/miniz.h b/Charcoal/Charcoal/libmobi-public/src/miniz.h new file mode 100644 index 0000000..50b3259 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/miniz.h @@ -0,0 +1,24 @@ +/** @file miniz.h + * @brief header file for third party miniz.c, zlib replacement + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_miniz_h +#define libmobi_miniz_h + +#define MINIZ_HEADER_FILE_ONLY +#define MINIZ_NO_STDIO +#define MINIZ_NO_ARCHIVE_APIS +#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES +#define MINIZ_NO_TIME +#define MINIZ_NO_ARCHIVE_WRITING_APIS + +#include "miniz.c" + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/mobi.h b/Charcoal/Charcoal/libmobi-public/src/mobi.h new file mode 100644 index 0000000..4afbd15 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobi.h @@ -0,0 +1,623 @@ +/** @file mobi.h + * @brief Libmobi main header file + * + * This file is installed with the library. + * Include it in your project with "#include ". + * See example of usage in mobitool.c, mobimeta.c, mobidrm.c + * + * Copyright (c) 2014-2022 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_mobi_h +#define libmobi_mobi_h + +#include +#include +#include +#include + +/** @brief Visibility attributes for symbol export */ +#if defined (__CYGWIN__) || defined (__MINGW32__) +#define MOBI_EXPORT __attribute__((visibility("default"))) __declspec(dllexport) extern +#elif defined (_WIN32) +#define MOBI_EXPORT __declspec(dllexport) +#else +#define MOBI_EXPORT __attribute__((__visibility__("default"))) +#endif + +/** + @brief Usually 32-bit values in mobi records + with value 0xffffffff mean "value not set" + */ +#define MOBI_NOTSET UINT32_MAX + +#define MOBI_ENCRYPTION_NONE 0 /**< Text record encryption type: none */ +#define MOBI_ENCRYPTION_V1 1 /**< Text record encryption type: old mobipocket */ +#define MOBI_ENCRYPTION_V2 2 /**< Text record encryption type: mobipocket */ + +#define MOBI_COMPRESSION_NONE 1 /**< Text record compression type: none */ +#define MOBI_COMPRESSION_PALMDOC 2 /**< Text record compression type: palmdoc */ +#define MOBI_COMPRESSION_HUFFCDIC 17480 /**< Text record compression type: huff/cdic */ + +#ifdef __cplusplus +extern "C" +{ +#endif + /** + @defgroup mobi_enums Exported enums + @{ + */ + + /** + @brief Error codes returned by functions + */ + typedef enum { + MOBI_SUCCESS = 0, /**< Generic success return value */ + MOBI_ERROR = 1, /**< Generic error return value */ + MOBI_PARAM_ERR = 2, /**< Wrong function parameter */ + MOBI_DATA_CORRUPT = 3, /**< Corrupted data */ + MOBI_FILE_NOT_FOUND = 4, /**< File not found */ + MOBI_FILE_ENCRYPTED = 5, /**< Unsupported encrypted data */ + MOBI_FILE_UNSUPPORTED = 6, /**< Unsupported document type */ + MOBI_MALLOC_FAILED = 7, /**< Memory allocation error */ + MOBI_INIT_FAILED = 8, /**< Initialization error */ + MOBI_BUFFER_END = 9, /**< Out of buffer error */ + MOBI_XML_ERR = 10, /**< XMLwriter error */ + MOBI_DRM_PIDINV = 11, /**< Invalid DRM PID */ + MOBI_DRM_KEYNOTFOUND = 12, /**< Key not found */ + MOBI_DRM_UNSUPPORTED = 13, /**< DRM support not included */ + MOBI_WRITE_FAILED = 14, /**< Writing to file failed */ + MOBI_DRM_EXPIRED = 15, /**< DRM expired */ + MOBI_DRM_RANDOM_ERR = 16 /**< DRM random bytes generation failed */ + } MOBI_RET; + + /** + @brief EXTH record types + */ + typedef enum { + EXTH_NUMERIC = 0, + EXTH_STRING = 1, + EXTH_BINARY = 2 + } MOBIExthType; + + /** + @brief EXTH record tags + */ + typedef enum { + EXTH_DRMSERVER = 1, + EXTH_DRMCOMMERCE = 2, + EXTH_DRMEBOOKBASE = 3, + + EXTH_TITLE = 99, /**< */ + EXTH_AUTHOR = 100, /**< */ + EXTH_PUBLISHER = 101, /**< */ + EXTH_IMPRINT = 102, /**< */ + EXTH_DESCRIPTION = 103, /**< */ + EXTH_ISBN = 104, /**< */ + EXTH_SUBJECT = 105, /**< */ + EXTH_PUBLISHINGDATE = 106, /**< */ + EXTH_REVIEW = 107, /**< */ + EXTH_CONTRIBUTOR = 108, /**< */ + EXTH_RIGHTS = 109, /**< */ + EXTH_SUBJECTCODE = 110, /**< */ + EXTH_TYPE = 111, /**< */ + EXTH_SOURCE = 112, /**< */ + EXTH_ASIN = 113, + EXTH_VERSION = 114, + EXTH_SAMPLE = 115, + EXTH_STARTREADING = 116, /**< Start reading */ + EXTH_ADULT = 117, /**< */ + EXTH_PRICE = 118, /**< */ + EXTH_CURRENCY = 119, /**< */ + EXTH_KF8BOUNDARY = 121, + EXTH_FIXEDLAYOUT = 122, /**< */ + EXTH_BOOKTYPE = 123, /**< */ + EXTH_ORIENTATIONLOCK = 124, /**< */ + EXTH_COUNTRESOURCES = 125, + EXTH_ORIGRESOLUTION = 126, /**< */ + EXTH_ZEROGUTTER = 127, /**< */ + EXTH_ZEROMARGIN = 128, /**< */ + EXTH_KF8COVERURI = 129, + EXTH_RESCOFFSET = 131, + EXTH_REGIONMAGNI = 132, /**< */ + + EXTH_DICTNAME = 200, /**< */ + EXTH_COVEROFFSET = 201, /**< */ + EXTH_THUMBOFFSET = 202, + EXTH_HASFAKECOVER = 203, + EXTH_CREATORSOFT = 204, + EXTH_CREATORMAJOR = 205, + EXTH_CREATORMINOR = 206, + EXTH_CREATORBUILD = 207, + EXTH_WATERMARK = 208, + EXTH_TAMPERKEYS = 209, + + EXTH_FONTSIGNATURE = 300, + + EXTH_CLIPPINGLIMIT = 401, + EXTH_PUBLISHERLIMIT = 402, + EXTH_UNK403 = 403, + EXTH_TTSDISABLE = 404, + EXTH_READFORFREE = 405, // uint32_t, rental related, ReadForFree + EXTH_RENTAL = 406, // uint64_t + EXTH_UNK407 = 407, + EXTH_UNK450 = 450, + EXTH_UNK451 = 451, + EXTH_UNK452 = 452, + EXTH_UNK453 = 453, + + EXTH_DOCTYPE = 501, /**< PDOC - Personal Doc; EBOK - ebook; EBSP - ebook sample; */ + EXTH_LASTUPDATE = 502, + EXTH_UPDATEDTITLE = 503, + EXTH_ASIN504 = 504, + EXTH_TITLEFILEAS = 508, + EXTH_CREATORFILEAS = 517, + EXTH_PUBLISHERFILEAS = 522, + EXTH_LANGUAGE = 524, /**< */ + EXTH_ALIGNMENT = 525, /**< */ + EXTH_CREATORSTRING = 526, + EXTH_PAGEDIR = 527, + EXTH_OVERRIDEFONTS = 528, /**< */ + EXTH_SORCEDESC = 529, + EXTH_DICTLANGIN = 531, + EXTH_DICTLANGOUT = 532, + EXTH_INPUTSOURCE = 534, + EXTH_CREATORBUILDREV = 535, + } MOBIExthTag; + + /** + @brief Types of files stored in database records + */ + typedef enum { + T_UNKNOWN, /**< unknown */ + /* markup */ + T_HTML, /**< html */ + T_CSS, /**< css */ + T_SVG, /**< svg */ + T_OPF, /**< opf */ + T_NCX, /**< ncx */ + /* images */ + T_JPG, /**< jpg */ + T_GIF, /**< gif */ + T_PNG, /**< png */ + T_BMP, /**< bmp */ + /* fonts */ + T_OTF, /**< otf */ + T_TTF, /**< ttf */ + /* media */ + T_MP3, /**< mp3 */ + T_MPG, /**< mp3 */ + T_PDF, /**< pdf */ + /* generic types */ + T_FONT, /**< encoded font */ + T_AUDIO, /**< audio resource */ + T_VIDEO, /**< video resource */ + T_BREAK /**< end of file */ + } MOBIFiletype; + + /** + @brief Metadata of file types + */ + typedef struct { + MOBIFiletype type; /**< MOBIFiletype type */ + char extension[5]; /**< file extension */ + char mime_type[30]; /**< mime-type */ + } MOBIFileMeta; + + /** + @brief Encoding types in MOBI header (offset 28) + */ + typedef enum { + MOBI_CP1252 = 1252, /**< cp-1252 encoding */ + MOBI_UTF8 = 65001, /**< utf-8 encoding */ + MOBI_UTF16 = 65002, /**< utf-16 encoding */ + } MOBIEncoding; + + /** @} */ + + /** + @defgroup raw_structs Exported structures for the raw, unparsed records metadata and data + @{ + */ + + /** + @brief Header of palmdoc database file + */ + typedef struct { + char name[33]; /**< 0: Database name, zero terminated, trimmed title (+author) */ + uint16_t attributes; /**< 32: Attributes bitfield, PALMDB_ATTRIBUTE_DEFAULT */ + uint16_t version; /**< 34: File version, PALMDB_VERSION_DEFAULT */ + uint32_t ctime; /**< 36: Creation time */ + uint32_t mtime; /**< 40: Modification time */ + uint32_t btime; /**< 44: Backup time */ + uint32_t mod_num; /**< 48: Modification number, PALMDB_MODNUM_DEFAULT */ + uint32_t appinfo_offset; /**< 52: Offset to application info (if present) or zero, PALMDB_APPINFO_DEFAULT */ + uint32_t sortinfo_offset; /**< 56: Offset to sort info (if present) or zero, PALMDB_SORTINFO_DEFAULT */ + char type[5]; /**< 60: Database type, zero terminated, PALMDB_TYPE_DEFAULT */ + char creator[5]; /**< 64: Creator type, zero terminated, PALMDB_CREATOR_DEFAULT */ + uint32_t uid; /**< 68: Used internally to identify record */ + uint32_t next_rec; /**< 72: Used only when database is loaded into memory, PALMDB_NEXTREC_DEFAULT */ + uint16_t rec_count; /**< 76: Number of records in the file */ + } MOBIPdbHeader; + + /** + @brief Metadata and data of a record. All records form a linked list. + */ + typedef struct MOBIPdbRecord { + uint32_t offset; /**< Offset of the record data from the start of the database */ + size_t size; /**< Calculated size of the record data */ + uint8_t attributes; /**< Record attributes */ + uint32_t uid; /**< Record unique id, usually sequential even numbers */ + unsigned char *data; /**< Record data */ + struct MOBIPdbRecord *next; /**< Pointer to the next record or NULL */ + } MOBIPdbRecord; + + /** + @brief Metadata and data of a EXTH record. All records form a linked list. + */ + typedef struct MOBIExthHeader { + uint32_t tag; /**< Record tag */ + uint32_t size; /**< Data size */ + void *data; /**< Record data */ + struct MOBIExthHeader *next; /**< Pointer to the next record or NULL */ + } MOBIExthHeader; + + /** + @brief EXTH tag metadata + */ + typedef struct { + MOBIExthTag tag; /**< Record tag id */ + MOBIExthType type; /**< EXTH_NUMERIC, EXTH_STRING or EXTH_BINARY */ + char *name; /**< Tag name */ + } MOBIExthMeta; + + /** + @brief Header of the Record 0 meta-record + */ + typedef struct { + /* PalmDOC header (extended), offset 0, length 16 */ + uint16_t compression_type; /**< 0; 1 == no compression, 2 = PalmDOC compression, 17480 = HUFF/CDIC compression */ + /* uint16_t unused; // 2; 0 */ + uint32_t text_length; /**< 4; uncompressed length of the entire text of the book */ + uint16_t text_record_count; /**< 8; number of PDB records used for the text of the book */ + uint16_t text_record_size; /**< 10; maximum size of each record containing text, always 4096 */ + uint16_t encryption_type; /**< 12; 0 == no encryption, 1 = Old Mobipocket Encryption, 2 = Mobipocket Encryption */ + uint16_t unknown1; /**< 14; usually 0 */ + } MOBIRecord0Header; + + /** + @brief MOBI header which follows Record 0 header + + All MOBI header fields are pointers. Some fields are not present in the header, then the pointer is NULL. + */ + typedef struct { + /* MOBI header, offset 16 */ + char mobi_magic[5]; /**< 16: M O B I { 77, 79, 66, 73 }, zero terminated */ + uint32_t *header_length; /**< 20: the length of the MOBI header, including the previous 4 bytes */ + uint32_t *mobi_type; /**< 24: mobipocket file type */ + MOBIEncoding *text_encoding; /**< 28: 1252 = CP1252, 65001 = UTF-8 */ + uint32_t *uid; /**< 32: unique id */ + uint32_t *version; /**< 36: mobipocket format */ + uint32_t *orth_index; /**< 40: section number of orthographic meta index. MOBI_NOTSET if index is not available. */ + uint32_t *infl_index; /**< 44: section number of inflection meta index. MOBI_NOTSET if index is not available. */ + uint32_t *names_index; /**< 48: section number of names meta index. MOBI_NOTSET if index is not available. */ + uint32_t *keys_index; /**< 52: section number of keys meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra0_index; /**< 56: section number of extra 0 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra1_index; /**< 60: section number of extra 1 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra2_index; /**< 64: section number of extra 2 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra3_index; /**< 68: section number of extra 3 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra4_index; /**< 72: section number of extra 4 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra5_index; /**< 76: section number of extra 5 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *non_text_index; /**< 80: first record number (starting with 0) that's not the book's text */ + uint32_t *full_name_offset; /**< 84: offset in record 0 (not from start of file) of the full name of the book */ + uint32_t *full_name_length; /**< 88: length of the full name */ + uint32_t *locale; /**< 92: first byte is main language: 09 = English, next byte is dialect, 08 = British, 04 = US */ + uint32_t *dict_input_lang; /**< 96: input language for a dictionary */ + uint32_t *dict_output_lang; /**< 100: output language for a dictionary */ + uint32_t *min_version; /**< 104: minimum mobipocket version support needed to read this file. */ + uint32_t *image_index; /**< 108: first record number (starting with 0) that contains an image (sequential) */ + uint32_t *huff_rec_index; /**< 112: first huffman compression record */ + uint32_t *huff_rec_count; /**< 116: huffman compression records count */ + uint32_t *datp_rec_index; /**< 120: section number of DATP record */ + uint32_t *datp_rec_count; /**< 124: DATP records count */ + uint32_t *exth_flags; /**< 128: bitfield. if bit 6 (0x40) is set, then there's an EXTH record */ + /* 32 unknown bytes, usually 0, related to encryption and unknown6 */ + /* unknown2 */ + /* unknown3 */ + /* unknown4 */ + /* unknown5 */ + uint32_t *unknown6; /**< 164: use MOBI_NOTSET , related to encryption*/ + uint32_t *drm_offset; /**< 168: offset to DRM key info in DRMed files. MOBI_NOTSET if no DRM */ + uint32_t *drm_count; /**< 172: number of entries in DRM info */ + uint32_t *drm_size; /**< 176: number of bytes in DRM info */ + uint32_t *drm_flags; /**< 180: some flags concerning DRM info, bit 0 set if password encryption */ + /* 8 unknown bytes 0? */ + /* unknown7 */ + /* unknown8 */ + uint16_t *first_text_index; /**< 192: section number of first text record */ + uint16_t *last_text_index; /**< 194: */ + uint32_t *fdst_index; /**< 192 (KF8) section number of FDST record */ + //uint32_t *unknown9; /**< 196: */ + uint32_t *fdst_section_count; /**< 196 (KF8) */ + uint32_t *fcis_index; /**< 200: section number of FCIS record */ + uint32_t *fcis_count; /**< 204: FCIS records count */ + uint32_t *flis_index; /**< 208: section number of FLIS record */ + uint32_t *flis_count; /**< 212: FLIS records count */ + uint32_t *unknown10; /**< 216: */ + uint32_t *unknown11; /**< 220: */ + uint32_t *srcs_index; /**< 224: section number of SRCS record */ + uint32_t *srcs_count; /**< 228: SRCS records count */ + uint32_t *unknown12; /**< 232: */ + uint32_t *unknown13; /**< 236: */ + /* uint16_t fill 0 */ + uint16_t *extra_flags; /**< 242: extra flags */ + uint32_t *ncx_index; /**< 244: section number of NCX record */ + uint32_t *unknown14; /**< 248: */ + uint32_t *fragment_index; /**< 248 (KF8) section number of fragments record */ + uint32_t *unknown15; /**< 252: */ + uint32_t *skeleton_index; /**< 252 (KF8) section number of SKEL record */ + uint32_t *datp_index; /**< 256: section number of DATP record */ + uint32_t *unknown16; /**< 260: */ + uint32_t *guide_index; /**< 260 (KF8) section number of guide record */ + uint32_t *unknown17; /**< 264: */ + uint32_t *unknown18; /**< 268: */ + uint32_t *unknown19; /**< 272: */ + uint32_t *unknown20; /**< 276: */ + char *full_name; /**< variable offset (full_name_offset): full name */ + } MOBIMobiHeader; + + /** + @brief Main structure holding all metadata and unparsed records data + + In case of hybrid KF7/KF8 file there are two Records 0. + In such case MOBIData is a circular linked list of two independent records, one structure per each Record 0 header. + Records data (MOBIPdbRecord structure) is not duplicated in such case - each struct holds same pointers to all records data. + */ + typedef struct MOBIData { + bool use_kf8; /**< Flag: if set to true (default), KF8 part of hybrid file is parsed, if false - KF7 part will be parsed */ + uint32_t kf8_boundary_offset; /**< Set to KF8 boundary rec number if present, otherwise: MOBI_NOTSET */ + unsigned char *drm_key; /**< @deprecated Will be removed in future versions */ + MOBIPdbHeader *ph; /**< Palmdoc database header structure or NULL if not loaded */ + MOBIRecord0Header *rh; /**< Record0 header structure or NULL if not loaded */ + MOBIMobiHeader *mh; /**< MOBI header structure or NULL if not loaded */ + MOBIExthHeader *eh; /**< Linked list of EXTH records or NULL if not loaded */ + MOBIPdbRecord *rec; /**< Linked list of palmdoc database records or NULL if not loaded */ + struct MOBIData *next; /**< Pointer to the other part of hybrid file or NULL if not a hybrid file */ + void *internals; /**< Used internally*/ + } MOBIData; + + /** @} */ // end of raw_structs group + + /** + @defgroup parsed_structs Exported structures for the parsed records metadata and data + @{ + */ + + /** + @brief Parsed FDST record + + FDST record contains offsets of main sections in RAWML - raw text data. + The sections are usually html part, css parts, svg part. + */ + typedef struct { + size_t fdst_section_count; /**< Number of main sections */ + uint32_t *fdst_section_starts; /**< Array of section start offsets */ + uint32_t *fdst_section_ends; /**< Array of section end offsets */ + } MOBIFdst; + + /** + @brief Parsed tag for an index entry + */ + typedef struct { + size_t tagid; /**< Tag id */ + size_t tagvalues_count; /**< Number of tag values */ + uint32_t *tagvalues; /**< Array of tag values */ + } MOBIIndexTag; + + /** + @brief Parsed INDX index entry + */ + typedef struct { + char *label; /**< Entry string, zero terminated */ + size_t tags_count; /**< Number of tags */ + MOBIIndexTag *tags; /**< Array of tags */ + } MOBIIndexEntry; + + /** + @brief Parsed INDX record + */ + typedef struct { + size_t type; /**< Index type: 0 - normal, 2 - inflection */ + size_t entries_count; /**< Index entries count */ + MOBIEncoding encoding; /**< Index encoding */ + size_t total_entries_count; /**< Total index entries count */ + size_t ordt_offset; /**< ORDT offset */ + size_t ligt_offset; /**< LIGT offset */ + size_t ligt_entries_count; /**< LIGT index entries count */ + size_t cncx_records_count; /**< Number of compiled NCX records */ + MOBIPdbRecord *cncx_record; /**< Link to CNCX record */ + MOBIIndexEntry *entries; /**< Index entries array */ + char *orth_index_name; /**< Orth index name */ + } MOBIIndx; + + /** + @brief Reconstructed source file. + + All file parts are organized in a linked list. + */ + typedef struct MOBIPart { + size_t uid; /**< Unique id */ + MOBIFiletype type; /**< File type */ + size_t size; /**< File size */ + unsigned char *data; /**< File data */ + struct MOBIPart *next; /**< Pointer to next part or NULL */ + } MOBIPart; + + /** + @brief Main structure containing reconstructed source parts and indices + */ + typedef struct { + size_t version; /**< Version of Mobipocket document */ + MOBIFdst *fdst; /**< Parsed FDST record or NULL if not present */ + MOBIIndx *skel; /**< Parsed skeleton index or NULL if not present */ + MOBIIndx *frag; /**< Parsed fragments index or NULL if not present */ + MOBIIndx *guide; /**< Parsed guide index or NULL if not present */ + MOBIIndx *ncx; /**< Parsed NCX index or NULL if not present */ + MOBIIndx *orth; /**< Parsed orth index or NULL if not present */ + MOBIIndx *infl; /**< Parsed infl index or NULL if not present */ + MOBIPart *flow; /**< Linked list of reconstructed main flow parts or NULL if not present */ + MOBIPart *markup; /**< Linked list of reconstructed markup files or NULL if not present */ + MOBIPart *resources; /**< Linked list of reconstructed resources files or NULL if not present */ + } MOBIRawml; + + /** @} */ // end of parsed_structs group + + /** + @defgroup mobi_export Functions exported by the library + @{ + */ + MOBI_EXPORT const char * mobi_version(void); + MOBI_EXPORT MOBI_RET mobi_load_file(MOBIData *m, FILE *file); + MOBI_EXPORT MOBI_RET mobi_load_filename(MOBIData *m, const char *path); + + MOBI_EXPORT MOBIData * mobi_init(void); + MOBI_EXPORT void mobi_free(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_parse_kf7(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_parse_kf8(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_parse_rawml(MOBIRawml *rawml, const MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_parse_rawml_opt(MOBIRawml *rawml, const MOBIData *m, bool parse_toc, bool parse_dict, bool reconstruct); + + MOBI_EXPORT MOBI_RET mobi_get_rawml(const MOBIData *m, char *text, size_t *len); + MOBI_EXPORT MOBI_RET mobi_dump_rawml(const MOBIData *m, FILE *file); + MOBI_EXPORT MOBI_RET mobi_decode_font_resource(unsigned char **decoded_font, size_t *decoded_size, MOBIPart *part); + MOBI_EXPORT MOBI_RET mobi_decode_audio_resource(unsigned char **decoded_resource, size_t *decoded_size, MOBIPart *part); + MOBI_EXPORT MOBI_RET mobi_decode_video_resource(unsigned char **decoded_resource, size_t *decoded_size, MOBIPart *part); + MOBI_EXPORT MOBI_RET mobi_get_embedded_source(unsigned char **data, size_t *size, const MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_get_embedded_log(unsigned char **data, size_t *size, const MOBIData *m); + + MOBI_EXPORT MOBIPdbRecord * mobi_get_record_by_uid(const MOBIData *m, const size_t uid); + MOBI_EXPORT MOBIPdbRecord * mobi_get_record_by_seqnumber(const MOBIData *m, const size_t uid); + MOBI_EXPORT MOBIPart * mobi_get_flow_by_uid(const MOBIRawml *rawml, const size_t uid); + MOBI_EXPORT MOBIPart * mobi_get_flow_by_fid(const MOBIRawml *rawml, const char *fid); + MOBI_EXPORT MOBIPart * mobi_get_resource_by_uid(const MOBIRawml *rawml, const size_t uid); + MOBI_EXPORT MOBIPart * mobi_get_resource_by_fid(const MOBIRawml *rawml, const char *fid); + MOBI_EXPORT MOBIPart * mobi_get_part_by_uid(const MOBIRawml *rawml, const size_t uid); + MOBI_EXPORT MOBI_RET mobi_get_fullname(const MOBIData *m, char *fullname, const size_t len); + MOBI_EXPORT size_t mobi_get_first_resource_record(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_text_maxsize(const MOBIData *m); + MOBI_EXPORT uint16_t mobi_get_textrecord_maxsize(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_kf8offset(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_kf8boundary_seqnumber(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_record_extrasize(const MOBIPdbRecord *record, const uint16_t flags); + MOBI_EXPORT size_t mobi_get_record_mb_extrasize(const MOBIPdbRecord *record, const uint16_t flags); + MOBI_EXPORT size_t mobi_get_fileversion(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_fdst_record_number(const MOBIData *m); + MOBI_EXPORT MOBIExthHeader * mobi_get_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag); + MOBI_EXPORT MOBIExthHeader * mobi_next_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag, MOBIExthHeader **start); + MOBI_EXPORT MOBI_RET mobi_delete_exthrecord_by_tag(MOBIData *m, const MOBIExthTag tag); + MOBI_EXPORT MOBI_RET mobi_add_exthrecord(MOBIData *m, const MOBIExthTag tag, const uint32_t size, const void *value); + MOBI_EXPORT MOBIExthMeta mobi_get_exthtagmeta_by_tag(const MOBIExthTag tag); + MOBI_EXPORT MOBIFileMeta mobi_get_filemeta_by_type(const MOBIFiletype type); + MOBI_EXPORT uint32_t mobi_decode_exthvalue(const unsigned char *data, const size_t size); + MOBI_EXPORT char * mobi_decode_exthstring(const MOBIData *m, const unsigned char *data, const size_t size); + MOBI_EXPORT struct tm * mobi_pdbtime_to_time(const long pdb_time); + MOBI_EXPORT const char * mobi_get_locale_string(const uint32_t locale); + MOBI_EXPORT size_t mobi_get_locale_number(const char *locale_string); + MOBI_EXPORT uint32_t mobi_get_orth_entry_offset(const MOBIIndexEntry *entry); + MOBI_EXPORT uint32_t mobi_get_orth_entry_length(const MOBIIndexEntry *entry); + MOBI_EXPORT MOBI_RET mobi_remove_hybrid_part(MOBIData *m, const bool remove_kf8); + + MOBI_EXPORT bool mobi_exists_mobiheader(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_fdst(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_skel_indx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_frag_indx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_guide_indx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_ncx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_orth(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_infl(const MOBIData *m); + MOBI_EXPORT bool mobi_is_hybrid(const MOBIData *m); + MOBI_EXPORT bool mobi_is_encrypted(const MOBIData *m); + MOBI_EXPORT bool mobi_is_mobipocket(const MOBIData *m); + MOBI_EXPORT bool mobi_is_dictionary(const MOBIData *m); + MOBI_EXPORT bool mobi_is_kf8(const MOBIData *m); + MOBI_EXPORT bool mobi_is_replica(const MOBIData *m); + MOBI_EXPORT bool mobi_is_rawml_kf8(const MOBIRawml *rawml); + MOBI_EXPORT MOBIRawml * mobi_init_rawml(const MOBIData *m); + MOBI_EXPORT void mobi_free_rawml(MOBIRawml *rawml); + + MOBI_EXPORT char * mobi_meta_get_title(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_author(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_publisher(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_imprint(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_description(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_isbn(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_subject(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_publishdate(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_review(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_contributor(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_copyright(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_asin(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_language(const MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_title(MOBIData *m, const char *title); + MOBI_EXPORT MOBI_RET mobi_meta_add_title(MOBIData *m, const char *title); + MOBI_EXPORT MOBI_RET mobi_meta_delete_title(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_author(MOBIData *m, const char *author); + MOBI_EXPORT MOBI_RET mobi_meta_add_author(MOBIData *m, const char *author); + MOBI_EXPORT MOBI_RET mobi_meta_delete_author(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_publisher(MOBIData *m, const char *publisher); + MOBI_EXPORT MOBI_RET mobi_meta_add_publisher(MOBIData *m, const char *publisher); + MOBI_EXPORT MOBI_RET mobi_meta_delete_publisher(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_imprint(MOBIData *m, const char *imprint); + MOBI_EXPORT MOBI_RET mobi_meta_add_imprint(MOBIData *m, const char *imprint); + MOBI_EXPORT MOBI_RET mobi_meta_delete_imprint(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_description(MOBIData *m, const char *description); + MOBI_EXPORT MOBI_RET mobi_meta_add_description(MOBIData *m, const char *description); + MOBI_EXPORT MOBI_RET mobi_meta_delete_description(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_isbn(MOBIData *m, const char *isbn); + MOBI_EXPORT MOBI_RET mobi_meta_add_isbn(MOBIData *m, const char *isbn); + MOBI_EXPORT MOBI_RET mobi_meta_delete_isbn(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_subject(MOBIData *m, const char *subject); + MOBI_EXPORT MOBI_RET mobi_meta_add_subject(MOBIData *m, const char *subject); + MOBI_EXPORT MOBI_RET mobi_meta_delete_subject(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_publishdate(MOBIData *m, const char *publishdate); + MOBI_EXPORT MOBI_RET mobi_meta_add_publishdate(MOBIData *m, const char *publishdate); + MOBI_EXPORT MOBI_RET mobi_meta_delete_publishdate(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_review(MOBIData *m, const char *review); + MOBI_EXPORT MOBI_RET mobi_meta_add_review(MOBIData *m, const char *review); + MOBI_EXPORT MOBI_RET mobi_meta_delete_review(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_contributor(MOBIData *m, const char *contributor); + MOBI_EXPORT MOBI_RET mobi_meta_add_contributor(MOBIData *m, const char *contributor); + MOBI_EXPORT MOBI_RET mobi_meta_delete_contributor(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_copyright(MOBIData *m, const char *copyright); + MOBI_EXPORT MOBI_RET mobi_meta_add_copyright(MOBIData *m, const char *copyright); + MOBI_EXPORT MOBI_RET mobi_meta_delete_copyright(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_asin(MOBIData *m, const char *asin); + MOBI_EXPORT MOBI_RET mobi_meta_add_asin(MOBIData *m, const char *asin); + MOBI_EXPORT MOBI_RET mobi_meta_delete_asin(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_language(MOBIData *m, const char *language); + MOBI_EXPORT MOBI_RET mobi_meta_add_language(MOBIData *m, const char *language); + MOBI_EXPORT MOBI_RET mobi_meta_delete_language(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_drm_setkey(MOBIData *m, const char *pid); + MOBI_EXPORT MOBI_RET mobi_drm_setkey_serial(MOBIData *m, const char *serial); + MOBI_EXPORT MOBI_RET mobi_drm_addvoucher(MOBIData *m, const char *serial, const time_t valid_from, const time_t valid_to, + const MOBIExthTag *tamperkeys, const size_t tamperkeys_count); + MOBI_EXPORT MOBI_RET mobi_drm_delkey(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_drm_decrypt(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_drm_encrypt(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_write_file(FILE *file, MOBIData *m); + /** @} */ // end of mobi_export group + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/mobidrm.1.in b/Charcoal/Charcoal/libmobi-public/src/mobidrm.1.in new file mode 100644 index 0000000..8cee764 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobidrm.1.in @@ -0,0 +1,124 @@ +.Dd February 16, 2022 +.Dt mobidrm 1 URM +.Os Unix +.Sh NAME +.Nm mobidrm +.Nd Utility for decryption and encryption of MOBI format ebook files. +.Sh SYNOPSIS +.Nm +.Fl d +.Op Fl o Ar dir +.Op Fl p Ar pid +.Op Fl s Ar serial +.Ar file +.Nm +.Fl e +.Op Fl o Ar dir +.Op Fl s Ar serial +.Op Fl f Ar date +.Op Fl t Ar date +.Ar file +.Nm +.Op Fl hv +.Sh DESCRIPTION +The program encrypts or decrypts MOBI files with DRM schemes used on eInk devices. It is powered by +.Nm libmobi +library. +.Pp +It may encrypt documents targeting particular device by using its serial number or applying generic DRM scheme targeting all supported readers. +.Pp +Optionally encryption may be valid only during chosen period. Kindles require both start and end date to be set. +This tool allows to specify only one date (start or end). +In such case the other date will be automatically set to respectively lowest (1970-01-01) or largest (10136-02-16) valid value. +.Pp +In case of hybrid files mobidrm separately encrypts both enclosed parts and produces two files: mobi for legacy format and azw3 for KF8 format. +.Pp +The program also decrypts documents. One must supply device serial number or document PID if DRM was applied for specific device. +.Pp +Invoked without arguments prints usage summary and exits. +.Pp +A list of flags and their descriptions. +.Pp +\fBDecryption flags\fR: +.Pp +.Bl -tag -width -indent +.It Fl d +Decrypt. This flag must be set in order to decrypt document. +.It Fl p Ar pid +Set optional decryption +.Ar pid +(may be specified multiple times). +.It Fl s Ar serial +Set optional device +.Ar serial +number (may be specified multiple times). +.El +.Pp +\fBEncryption flags\fR: +.Bl -tag -width -indent +.It Fl e +Encrypt. This flag must be set in order to encrypt document. +.It Fl f Ar date +Set optional validity period \fBfrom\fR +.Ar date +formatted as yyyy-mm-dd. Document will not be valid before this date. +.It Fl s Ar serial +Set optional device +.Ar serial +number. If not set document will be encrypted with generic reader key. This flag may be specified +multiple times to target multiple devices. +.It Fl t Ar date +Set optional validity period \fBto\fR +.Ar date +formatted as yyyy-mm-dd. Document will expire after this date. +.El +.Pp +\fBCommon flags\fR: +.Bl -tag -width -indent +.It Fl o Ar dir +Save output to +.Ar dir +folder. +.It Fl h +Show usage summary and exit. +.It Fl v +Show version and exit. +.El +.Pp +.Sh EXAMPLES +The following command decrypts document using given serial number. Decrypted output will be saved to /tmp folder. +.Pp +.Dl % mobidrm -d -s B001XXXXXXXXXXXX -o /tmp example.mobi +.Pp +The following command decrypts document trying multiple PIDs. +.Pp +.Dl % mobidrm -d -p XXXXXXXXX1 -p XXXXXXXXX2 example.mobi +.Pp +The following command encrypts document targeting two devices using their serial numbers. Document will be readable only on those devices. +.Pp +.Dl % mobidrm -e -s B001XXXXXXXXXX01 -s B001XXXXXXXXXX02 example.mobi +.Pp +The following command encrypts document for device wth given serial number. Document will only be valid within given period (inclusive). +.Pp +.Dl % mobidrm -e -s B001XXXXXXXXXX01 -f 2021-01-01 -t 2021-01-31 example.mobi +.Sh RETURN VALUES +The +.Nm +utility returns 0 on success, 1 on error. +.Sh COPYRIGHT +Copyright (C) 2021-2022 Bartek Fabiszewski. +.Pp +Released under LGPL version 3 or any later (same as +.Nm libmobi Ns +). +.Sh WEB SITE +Visit http://www.fabiszewski.net for details. +.Sh DIAGNOSTICS +For diagnostics +.Nm libmobi +must be configured with +.Fl Fl enable-debug +option. +.Sh SEE ALSO +.Xr mobimeta 1 +.Xr mobitool 1 diff --git a/Charcoal/Charcoal/libmobi-public/src/mobidrm.c b/Charcoal/Charcoal/libmobi-public/src/mobidrm.c new file mode 100644 index 0000000..971334a --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobidrm.c @@ -0,0 +1,488 @@ +/** @file mobidrm.c + * + * @brief mobidrm + * + * Copyright (c) 2021 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define VOUCHERS_COUNT_MAX 20 + +/* command line options */ +bool decrypt_opt = false; +bool encrypt_opt = false; +bool expiry_opt = false; + +/* options values */ +char *pid[VOUCHERS_COUNT_MAX]; +char *serial[VOUCHERS_COUNT_MAX]; +size_t serial_count = 0; +size_t pid_count = 0; +time_t valid_from = -1; +time_t valid_to = -1; + + +/** + @brief Print usage info + @param[in] progname Executed program name + */ +static void print_usage(const char *progname) { + printf("usage: %s [-d | -e] [-hv] [-p pid] [-f date] [-t date] [-s serial] [-o dir] filename\n", progname); + printf(" without arguments prints document metadata and exits\n\n"); + + printf(" Decrypt options:\n"); + printf(" -d decrypt (required)\n"); + printf(" -p pid set decryption pid (may be specified multiple times)\n"); + printf(" -s serial set device serial (may be specified multiple times)\n\n"); + + printf(" Encrypt options:\n"); + printf(" -e encrypt (required)\n"); + printf(" -s serial set device serial (may be specified multiple times)\n"); + printf(" -f date set validity period from date (yyyy-mm-dd) when encrypting (inclusive)\n"); + printf(" -t date set validity period to date (yyyy-mm-dd) when encrypting (inclusive)\n\n"); + + printf(" Common options:\n"); + printf(" -o dir save output to dir folder\n"); + printf(" -h show this usage summary and exit\n"); + printf(" -v show version and exit\n"); +} + +/** + @brief Applies DRM + + @param[in,out] m MOBIData structure + @param[in] use_kf8 In case of hybrid file process KF8 part if true, the other part otherwise + @return SUCCESS or ERROR + */ +static int do_encrypt(MOBIData *m, bool use_kf8) { + + MOBI_RET mobi_ret; + + if (mobi_is_hybrid(m)) { + mobi_ret = mobi_remove_hybrid_part(m, !use_kf8); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error removing hybrid part (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + printf("\nProcessing file version %zu from hybrid file\n", mobi_get_fileversion(m)); + } + + MOBIExthTag *tags = NULL; + MOBIExthTag amazonkeys[] = { EXTH_WATERMARK, EXTH_TTSDISABLE, EXTH_CLIPPINGLIMIT, EXTH_READFORFREE, EXTH_RENTAL, EXTH_UNK407 }; + MOBIExthTag tamperkeys[ARRAYSIZE(amazonkeys)] = { 0 }; + size_t tags_count = 0; + + if (mobi_get_fileversion(m) >= 4 && m->eh) { + // EXTH tamperproof keys are required with encryption scheme 2 in mobi version 8 + // and are supported since version 4. + // Amazon software by default includes tags: 208, 404, 401, 405, 406, 407 in DRM scheme. + // Any change in tags that are included invalidates DRM. + // You can secure any tag you want, we just add dummy watermark (208) if it is not already present in file + // to satisfy requirements. + if (mobi_get_exthrecord_by_tag(m, EXTH_WATERMARK) == NULL) { + char watermark[] = "aHR0cHM6Ly9naXRodWIuY29tL2JmYWJpc3pld3NraS9saWJtb2Jp"; + mobi_add_exthrecord(m, EXTH_WATERMARK, (uint32_t) strlen(watermark), watermark); + } + tamperkeys[0] = amazonkeys[0]; + tags_count++; + // If any of the Amazon default tags is present in file, secure it too. + // You can also add any of them with mobimeta before running mobidrm. + for (size_t i = 1; i < ARRAYSIZE(amazonkeys); i++) { + // if exth record exists in mobi file + if (mobi_get_exthrecord_by_tag(m, amazonkeys[i]) != NULL) { + // add it tamperproof keys + tamperkeys[tags_count++] = amazonkeys[i]; + } + } + + tags = tamperkeys; + } + + for (size_t i = 0; i < serial_count; i++) { + mobi_ret = mobi_drm_addvoucher(m, serial[i], valid_from, valid_to, tags, tags_count); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error adding encryption voucher (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + } + if (serial_count == 0) { + mobi_ret = mobi_drm_addvoucher(m, NULL, valid_from, valid_to, tags, tags_count); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error adding encryption voucher (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + } + + mobi_ret = mobi_drm_encrypt(m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error encrypting document (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + + printf("Encrypting with encryption type %u\n", m->rh->encryption_type); + if (m->rh->encryption_type == MOBI_ENCRYPTION_V1 && serial_count) { + printf("Warning! Encryption with device serial number is not supported with this encryption scheme. Skipping serial...\n"); + } + if (valid_from != -1) { + printf("Drm validity period from %s", ctime(&valid_from)); + } + if (valid_to != -1) { + printf("Drm validity period to %s", ctime(&valid_to)); + } + return SUCCESS; +} + +/** + @brief Removes DRM + + @param[in,out] m MOBIData structure + @return SUCCESS or ERROR + */ +static int do_decrypt(MOBIData *m) { + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_RENTAL); + if (exth) { + uint32_t is_rental = mobi_decode_exthvalue(exth->data, exth->size); + if (is_rental) { + printf("Can't remove DRM from rented documents\n"); + return ERROR; + } + } + uint16_t encryption_type = m->rh->encryption_type; + printf("Removing encryption type %u\n", encryption_type); + bool has_key = false; + if (pid_count) { + for (size_t i = 0; i < pid_count; i++) { + if (set_decryption_pid(m, pid[i]) == SUCCESS) { + has_key = true; + break; + } + } + } + if (!has_key && serial_count) { + for (size_t i = 0; i < serial_count; i++) { + if (set_decryption_serial(m, serial[i]) == SUCCESS) { + break; + } + } + } + MOBI_RET mobi_ret = mobi_drm_decrypt(m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error encrypting document (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + + if (encryption_type == MOBI_ENCRYPTION_V2) { + // remove EXTH records that impose restrictions or are DRM related + MOBIExthTag drmkeys[] = { EXTH_TAMPERKEYS, EXTH_WATERMARK, EXTH_TTSDISABLE, EXTH_CLIPPINGLIMIT, EXTH_READFORFREE, EXTH_RENTAL, EXTH_UNK407 }; + for (size_t i = 0; i < ARRAYSIZE(drmkeys); i++) { + mobi_ret = mobi_delete_exthrecord_by_tag(m, drmkeys[i]); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error removing EXTH record %u\n", drmkeys[i]); + return ERROR; + } + } + } + return SUCCESS; +} + +/** + @brief Main routine that calls optional subroutines + + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int loadfilename(const char *fullpath) { + + static int run_count = 0; + run_count++; + + bool use_kf8 = run_count == 1 ? false : true; + + /* Initialize main MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Memory allocation failed\n"); + return ERROR; + } + + errno = 0; + FILE *file = fopen(fullpath, "rb"); + if (file == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", fullpath, strerror(errsv)); + mobi_free(m); + return ERROR; + } + + /* MOBIData structure will be filled with loaded document data and metadata */ + MOBI_RET mobi_ret = mobi_load_file(m, file); + fclose(file); + + if (mobi_ret != MOBI_SUCCESS) { + printf("Error while loading document (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + if (run_count == 1) { + print_summary(m); + } + + // save is hybrid result here, as file may be modified later + bool is_hybrid = mobi_is_hybrid(m); + + int ret = SUCCESS; + const char *suffix; + if (encrypt_opt) { + // encrypt + if (mobi_is_encrypted(m)) { + mobi_free(m); + printf("Document is already encrypted\n"); + return ERROR; + } + ret = do_encrypt(m, use_kf8); + if (ret != SUCCESS) { + mobi_free(m); + return ERROR; + } + suffix = "encrypted"; + } else { + // decrypt + if (!mobi_is_encrypted(m)) { + mobi_free(m); + printf("Document is not encrypted\n"); + return ERROR; + } + ret = do_decrypt(m); + if (ret != SUCCESS) { + mobi_free(m); + return ERROR; + } + suffix = "decrypted"; + } + + ret = save_mobi(m, fullpath, suffix); + if (ret != SUCCESS) { + mobi_free(m); + return ERROR; + } + + /* Free MOBIData structure */ + mobi_free(m); + + /* In case of encrypting hybrid file proceed with KF8 part */ + if (encrypt_opt && is_hybrid && use_kf8 == false) { + loadfilename(fullpath); + } + return SUCCESS; +} + +/** + @brief Parse ISO8601 date into tm structure + + @param[in,out] tm Structure to be filled + @param[in] date_str Input date string + @return SUCCESS or ERROR + */ +static int parse_date(struct tm *tm, const char *date_str) { + memset(tm, '\0', sizeof(*tm)); + int year; + int month; + int day; + if (sscanf(date_str, "%5d-%2d-%2d", &year, &month, &day) != 3) { + return ERROR; + } + if (year < 1000 || month < 1 || month > 12 || day < 1 || day > 31) { + return ERROR; + } + + tm->tm_year = year - 1900; + tm->tm_mon = month - 1; + tm->tm_mday = day; + tm->tm_isdst = -1; + + return SUCCESS; +} + +/** + @brief Main + + @param[in] argc Arguments count + @param[in] argv Arguments array + @return SUCCESS (0) or ERROR (1) + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + print_usage(argv[0]); + return ERROR; + } + opterr = 0; + int c; + while ((c = getopt(argc, argv, "def:ho:p:s:t:vx:")) != -1) { + switch(c) { + case 'd': + if (encrypt_opt) { + printf("Options -d and -e can't be used together.\n"); + return ERROR; + } + decrypt_opt = true; + break; + case 'e': + if (decrypt_opt) { + printf("Options -d and -e can't be used together.\n"); + return ERROR; + } + encrypt_opt = true; + break; + case 'f': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + struct tm from; + if (parse_date(&from, optarg) != SUCCESS) { + printf("Wrong valid from date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + valid_from = mktime(&from); + if (valid_from == -1) { + printf("Unparsable valid from date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + expiry_opt = true; + break; + case 'o': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + size_t outdir_length = strlen(optarg); + if (outdir_length >= FILENAME_MAX - 1) { + printf("Output directory name too long\n"); + return ERROR; + } + strncpy(outdir, optarg, FILENAME_MAX - 1); + normalize_path(outdir); + if (!dir_exists(outdir)) { + printf("Output directory is not valid\n"); + return ERROR; + } + if (optarg[outdir_length - 1] != separator) { + // append separator + if (outdir_length >= FILENAME_MAX - 2) { + printf("Output directory name too long\n"); + return ERROR; + } + outdir[outdir_length++] = separator; + outdir[outdir_length] = '\0'; + } + outdir_opt = true; + break; + case 'p': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + if (pid_count < VOUCHERS_COUNT_MAX) { + pid[pid_count++] = optarg; + } else { + printf("Maximum PIDs count reached, skipping PID...\n"); + } + break; + case 's': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + if (serial_count < VOUCHERS_COUNT_MAX) { + serial[serial_count++] = optarg; + } else { + printf("Maximum serial numbers count reached, skipping serial...\n"); + } + break; + case 't': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + struct tm to; + if (parse_date(&to, optarg) != SUCCESS) { + printf("Wrong valid to date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + to.tm_hour = 23; + to.tm_min = 59; + to.tm_sec = 59; + valid_to = mktime(&to); + if (valid_to == -1) { + printf("Unparsable valid to date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + expiry_opt = true; + break; + case 'v': + printf("mobidrm build: " __DATE__ " " __TIME__ " (" COMPILER ")\n"); + printf("libmobi: %s\n", mobi_version()); + return SUCCESS; + case '?': + if (isprint(optopt)) { + fprintf(stderr, "Unknown option `-%c'\n", optopt); + } + else { + fprintf(stderr, "Unknown option character `\\x%x'\n", optopt); + } + print_usage(argv[0]); + return ERROR; + case 'h': + default: + print_usage(argv[0]); + return SUCCESS; + } + } + + if (argc <= optind) { + printf("Missing filename\n"); + print_usage(argv[0]); + return ERROR; + } + + if (!decrypt_opt && !encrypt_opt) { + printf("One of -d (decrypt) and -e (encrypt) options is required\n"); + print_usage(argv[0]); + return ERROR; + } + + if (!encrypt_opt && expiry_opt) { + printf("Expiration flags can only be used with -e (encrypt)\n"); + print_usage(argv[0]); + return ERROR; + } + + if (!decrypt_opt && pid_count) { + printf("PID can only be used with -d (decrypt)\n"); + print_usage(argv[0]); + return ERROR; + } + + int ret = 0; + char filename[FILENAME_MAX]; + strncpy(filename, argv[optind], FILENAME_MAX - 1); + filename[FILENAME_MAX - 1] = '\0'; + normalize_path(filename); + + ret = loadfilename(filename); + + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/mobimeta.1.in b/Charcoal/Charcoal/libmobi-public/src/mobimeta.1.in new file mode 100644 index 0000000..dde1939 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobimeta.1.in @@ -0,0 +1,92 @@ +.Dd February 16, 2022 +.Dt mobimeta 1 URM +.Os Unix +.Sh NAME +.Nm mobimeta +.Nd Utility for modifying metadata of MOBI format ebook files. +.Sh SYNOPSIS +.Nm +.Op Fl a Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +.Op Fl d Ar meta Ns Oo , Ns Ar meta Ns , Ns Ar ... Oc +.Op Fl s Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +.if !'@ENCRYPTION_OPT@'yes' .ig +.Op Fl p Ar pid +.Op Fl P Ar serial +.. +.Op Fl hv +.Ar filein +.Op Ar fileout +.Sh DESCRIPTION +The program handles .prc, .mobi, .azw, .azw3, .azw4, some .pdb documents. It is powered by +.Nm libmobi +library. +.Pp +Invoked without arguments prints document metadata and exits. If +.Ar fileout +is specified, modified document will be saved with this name, otherwise original input +.Ar filein +will be modified. +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent +.It Fl a Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +add (append) metadata +.It Fl d Ar meta Ns Oo , Ns Ar meta Ns , Ns Ar ... Oc +delete metadata +.It Fl s Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +set (replace) metadata +.It Ar meta +for a list of valid named meta keys try +.Nm Bro Fl a | Fl d | Fl s Brc Ar \&? . +If meta is an integer it will be treated as a numeric EXTH record key (expert usage). +.It Ar value +new value that will be set for a given meta key +.if !'@ENCRYPTION_OPT@'yes' .ig +.It Fl p Ar pid +set pid for decryption +.It Fl P Ar serial +set device serial number for decryption +.. +.It Fl h +show usage summary and exit +.It Fl v +show version and exit +.El +.Pp +.Sh EXAMPLES +The following command will set new title, new author and will delete all publisher metadata (if any). +.Pp +.Dl % mobimeta -s title="My title",author="My name" -d publisher example.mobi +.Pp +The following command appends EXTH record identified by its numeric key 204 with numeric value 201. +.Pp +.Dl % mobimeta -a 204=201 example.mobi +.Pp +The following command will list valid meta named keys. +.Pp +.Dl % mobimeta -a \&?\& +.Pp +Or in case your shell expands quotation mark: +.Pp +.Dl % mobimeta -a \&"?"\& +.Sh RETURN VALUES +The +.Nm +utility returns 0 on success, 1 on error. +.Sh COPYRIGHT +Copyright (C) 2014-2022 Bartek Fabiszewski. +.Pp +Released under LGPL version 3 or any later (same as +.Nm libmobi Ns +). +.Sh WEB SITE +Visit http://www.fabiszewski.net for details. +.Sh DIAGNOSTICS +For diagnostics +.Nm libmobi +must be configured with +.Fl Fl enable-debug +option. +.Sh SEE ALSO +.Xr mobitool 1 +.Xr mobidrm 1 diff --git a/Charcoal/Charcoal/libmobi-public/src/mobimeta.c b/Charcoal/Charcoal/libmobi-public/src/mobimeta.c new file mode 100644 index 0000000..750bc65 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobimeta.c @@ -0,0 +1,398 @@ +/** @file mobimeta.c + * + * @brief mobimeta + * + * @example mobimeta.c + * Program for testing libmobi library + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* encryption */ +#ifdef USE_ENCRYPTION +# define PRINT_ENC_USG " [-p pid] [-P serial]" +# define PRINT_ENC_ARG "p:P:" +#else +# define PRINT_ENC_USG "" +# define PRINT_ENC_ARG "" +#endif + +/* command line options */ +#ifdef USE_ENCRYPTION +bool setpid_opt = false; +bool setserial_opt = false; +#endif + +/* options values */ +#ifdef USE_ENCRYPTION +char *pid = NULL; +char *serial = NULL; +#endif + +#define META_SIZE ARRAYSIZE(meta_functions) +#define ACTIONS_SIZE ARRAYSIZE(actions) + +#if HAVE_ATTRIBUTE_NORETURN +static void exit_with_usage(const char *progname) __attribute__((noreturn)); +#else +static void exit_with_usage(const char *progname); +#endif + +/** + @brief Meta handling functions + */ +typedef MOBI_RET (*MetaFunAdd)(MOBIData *m, const char *string); +typedef MOBI_RET (*MetaFunDel)(MOBIData *m); + +/** + @brief Meta functions structure + */ +typedef struct { + const char *name; + MetaFunAdd function_add; + MetaFunAdd function_set; + MetaFunDel function_del; +} CB; + +const CB meta_functions[] = { + { "author", mobi_meta_add_author, mobi_meta_set_author, mobi_meta_delete_author }, + { "title", mobi_meta_add_title, mobi_meta_set_title, mobi_meta_delete_title }, + { "publisher", mobi_meta_add_publisher, mobi_meta_set_publisher, mobi_meta_delete_publisher }, + { "imprint", mobi_meta_add_imprint, mobi_meta_set_imprint, mobi_meta_delete_imprint }, + { "description", mobi_meta_add_description, mobi_meta_set_description, mobi_meta_delete_description }, + { "isbn", mobi_meta_add_isbn, mobi_meta_set_isbn, mobi_meta_delete_isbn }, + { "subject", mobi_meta_add_subject, mobi_meta_set_subject, mobi_meta_delete_subject }, + { "publishdate", mobi_meta_add_publishdate, mobi_meta_set_publishdate, mobi_meta_delete_publishdate }, + { "review", mobi_meta_add_review, mobi_meta_set_review, mobi_meta_delete_review }, + { "contributor", mobi_meta_add_contributor, mobi_meta_set_contributor, mobi_meta_delete_contributor }, + { "copyright", mobi_meta_add_copyright, mobi_meta_set_copyright, mobi_meta_delete_copyright }, + { "asin", mobi_meta_add_asin, mobi_meta_set_asin, mobi_meta_delete_asin }, + { "language", mobi_meta_add_language, mobi_meta_set_language, mobi_meta_delete_language }, +}; + +/** + @brief Print usage info + @param[in] progname Executed program name + */ +static void exit_with_usage(const char *progname) { + char *p = strrchr(progname, separator); + if (p) { progname = ++p; } + printf("usage: %s [-a | -s meta=value[,meta=value,...]] [-d meta[,meta,...]]" PRINT_ENC_USG " [-hv] filein [fileout]\n", progname); + printf(" without arguments prints document metadata and exits\n"); + printf(" -a ? list valid meta named keys\n"); + printf(" -a meta=value add metadata\n"); + printf(" -d meta delete metadata\n"); + printf(" -s meta=value set metadata\n"); +#ifdef USE_ENCRYPTION + printf(" -p pid set pid for decryption\n"); + printf(" -P serial set device serial for decryption\n"); +#endif + printf(" -h show this usage summary and exit\n"); + printf(" -v show version and exit\n"); + exit(ERROR); +} + +/** + @brief Check whether string is integer + @param[in] string String + @return True if string represents integer + */ +static bool isinteger(const char *string) { + if (*string == '\0') { return false; } + while (*string) { + if (!isdigit(*string++)) { return false; } + } + return true; +} + +/** + @brief Parse suboption's list key=value[,key=value,...] + and get first key-value pair. + @param[in,out] subopts List of suboptions + @param[in,out] token Will be filled with first found key name or NULL if missing + @param[in,out] value Will be filled with first found key value or NULL if missing + @return True if there are more pairs to parse + */ +static bool parsesubopt(char **subopts, char **token, char **value) { + if (!**subopts) { return false; } + *token = NULL; + *value = NULL; + char *p = NULL; + while ((p = (*subopts)++) && *p) { + if (*p == ',') { + *p = '\0'; + return true; + } + if (!*token) { *token = p; } + if (*p == '=') { + *p = '\0'; + *value = ++p; + } + } + return false; +} + +/** + @brief Get matching token from meta functions array + @param[in] token Meta token name + @return Index in array,-1 if not found + */ +static int get_meta(const char *token) { + for (int i = 0; i < (int) META_SIZE; i++) { + if (strcmp(token, meta_functions[i].name) == 0) { + return i; + } + } + return -1; +} + +/** + @brief Main + + @param[in] argc Arguments count + @param[in] argv Arguments array + @return SUCCESS (0) or ERROR (1) + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + exit_with_usage(argv[0]); + } + + typedef struct { + int command; + int meta; + char *value; + } Action; + Action actions[100]; + + size_t cmd_count = 0; + + char *token = NULL; + char *value = NULL; + char *subopts; + int opt; + int subopt; + bool parse; + while ((opt = getopt(argc, argv, "a:d:hs:" PRINT_ENC_ARG "v")) != -1) { + switch (opt) { + case 'a': + case 'd': + case 's': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", opt); + return ERROR; + } + subopts = optarg; + parse = true; + while (parse) { + parse = parsesubopt(&subopts, &token, &value); + if (token && (subopt = get_meta(token)) >= 0) { + if ((value == NULL || strlen(value) == 0) && opt != 'd') { + printf("Missing value for suboption '%s'\n\n", meta_functions[subopt].name); + exit_with_usage(argv[0]); + } + if (cmd_count < (ACTIONS_SIZE)) { + actions[cmd_count++] = (Action) { opt, subopt, value }; + } + } else if (token && isinteger(token)) { + if ((value == NULL || strlen(value) == 0) && opt != 'd') { + printf("Missing value for suboption '%s'\n\n", token); + exit_with_usage(argv[0]); + } + if (cmd_count < (ACTIONS_SIZE)) { + /* mark numeric meta with upper opt */ + actions[cmd_count++] = (Action) { toupper(opt), atoi(token), value }; + } + } else { + if (token == NULL || token[0] != '?') { + printf("Unknown meta: %s\n", token ? token : optarg); + } + printf("Valid named meta keys:\n"); + for (size_t i = 0; i < META_SIZE; i++) { + printf(" %s\n", meta_functions[i].name); + } + printf("\n"); + if (token == NULL || token[0] != '?') { + exit_with_usage(argv[0]); + } + return SUCCESS; + } + } + break; +#ifdef USE_ENCRYPTION + case 'p': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", opt); + return ERROR; + } + setpid_opt = true; + pid = optarg; + break; + case 'P': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", opt); + return ERROR; + } + setserial_opt = true; + serial = optarg; + break; +#endif + case 'v': + printf("mobimeta build: " __DATE__ " " __TIME__ " (" COMPILER ")\n"); + printf("libmobi: %s\n", mobi_version()); + return 0; + case '?': + if (isprint(optopt)) { + printf("Unknown option `-%c'\n", optopt); + } + else { + printf("Unknown option character `\\x%x'\n", optopt); + } + exit_with_usage(argv[0]); + case 'h': + default: + exit_with_usage(argv[0]); + } + } + + int file_args = argc - optind; + if (file_args <= 0) { + printf("Missing filename\n"); + exit_with_usage(argv[0]); + } + char infile[FILENAME_MAX]; + strncpy(infile, argv[optind], FILENAME_MAX - 1); + infile[FILENAME_MAX - 1] = '\0'; + normalize_path(infile); + + if (file_args >= 2) { optind++; } + + char outfile[FILENAME_MAX]; + strncpy(outfile, argv[optind], FILENAME_MAX - 1); + outfile[FILENAME_MAX - 1] = '\0'; + normalize_path(outfile); + + /* Initialize MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Libmobi initialization failed\n"); + return ERROR; + } + + /* read */ + FILE *file_in = fopen(infile, "rb"); + if (file_in == NULL) { + mobi_free(m); + int errsv = errno; + printf("Error opening file: %s (%s)\n", infile, strerror(errsv)); + return ERROR; + } + MOBI_RET mobi_ret = mobi_load_file(m, file_in); + fclose(file_in); + if (mobi_ret != MOBI_SUCCESS) { + mobi_free(m); + printf("Error loading file (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + +#ifdef USE_ENCRYPTION + if (setpid_opt || setserial_opt) { + int ret = set_decryption_key(m, serial, pid); + if (ret != SUCCESS) { + mobi_free(m); + return ret; + } + } +#endif + + if (cmd_count == 0) { + print_summary(m); + print_exth(m); + mobi_free(m); + return SUCCESS; + } + + for (size_t i = 0; i < cmd_count; i++) { + Action action = actions[i]; + MOBIExthMeta tag; + mobi_ret = MOBI_SUCCESS; + switch (action.command) { + /* named meta */ + case 'a': + mobi_ret = meta_functions[action.meta].function_add(m, action.value); + break; + case 'd': + mobi_ret = meta_functions[action.meta].function_del(m); + break; + case 's': + mobi_ret = meta_functions[action.meta].function_set(m, action.value); + break; + /* numeric exth */ + case 'A': + tag = mobi_get_exthtagmeta_by_tag((MOBIExthTag) action.meta); + if (tag.name && tag.type == EXTH_NUMERIC && isinteger(action.value)) { + uint32_t numeric = (uint32_t) atoi(action.value); + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, sizeof(uint32_t), &numeric); + } else { + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, (uint32_t) strlen(action.value), action.value); + } + break; + case 'D': + mobi_ret = mobi_delete_exthrecord_by_tag(m, (MOBIExthTag) action.meta); + break; + case 'S': + mobi_ret = mobi_delete_exthrecord_by_tag(m, (MOBIExthTag) action.meta); + if (mobi_ret != MOBI_SUCCESS) { break; } + tag = mobi_get_exthtagmeta_by_tag((MOBIExthTag) action.meta); + if (tag.name && tag.type == EXTH_NUMERIC && isinteger(action.value)) { + uint32_t numeric = (uint32_t) atoi(action.value); + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, sizeof(uint32_t), &numeric); + } else { + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, (uint32_t) strlen(action.value), action.value); + } + break; + } + if (mobi_ret != MOBI_SUCCESS) { + printf("Metadata modification failed (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + } + + /* write */ + printf("Saving %s...\n", outfile); + FILE *file_out = fopen(outfile, "wb"); + if (file_out == NULL) { + mobi_free(m); + int errsv = errno; + printf("Error opening file: %s (%s)\n", outfile, strerror(errsv)); + return ERROR; + } + mobi_ret = mobi_write_file(file_out, m); + fclose(file_out); + if (mobi_ret != MOBI_SUCCESS) { + mobi_free(m); + printf("Error writing file (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + + /* Free MOBIData structure */ + mobi_free(m); + + return SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/mobitool.1.in b/Charcoal/Charcoal/libmobi-public/src/mobitool.1.in new file mode 100644 index 0000000..0df918e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobitool.1.in @@ -0,0 +1,98 @@ +.Dd February 16, 2022 +.Dt mobitool 1 URM +.Os Unix +.Sh NAME +.Nm mobitool +.Nd Utility for handling MOBI format ebook files. +.Sh SYNOPSIS +.Nm +.if '@XMLWRITER_OPT@'yes' .ig +.Op Fl cdhimrstuvx7 +.. +.if !'@XMLWRITER_OPT@'yes' .ig +.Op Fl cdehimrstuvx7 +.. +.Op Fl o Ar dir +.if !'@ENCRYPTION_OPT@'yes' .ig +.Op Fl p Ar pid +.Op Fl P Ar serial +.. +.Ar file +.Sh DESCRIPTION +The program handles .prc, .mobi, .azw, .azw3, .azw4, some .pdb documents. It is powered by +.Nm libmobi +library. +.Pp +Invoked without arguments prints document metadata and exits. +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent +.It Fl c +dump cover +.It Fl d +dump rawml text record +.if !'@XMLWRITER_OPT@'yes' .ig +.It Fl e +convert mobi to epub +.. +.It Fl h +show usage summary and exit +.It Fl i +print detailed metadata +.It Fl m +print records metadata +.It Fl o Ar dir +save output to dir folder +.if !'@ENCRYPTION_OPT@'yes' .ig +.It Fl p Ar pid +set pid for decryption +.It Fl P Ar serial +set device serial number for decryption +.. +.It Fl r +dump raw records +.It Fl s +dump recreated source files +.It Fl t +split hybrid file into two parts: mobi and azw3 +.It Fl u +show rusage (diagnostics) +.It Fl v +show version and exit +.It Fl x +extract conversion source and log (if present) +.It Fl 7 +parse KF7 part of hybrid file (by default KF8 part is parsed) +.El +.Pp +.Sh EXAMPLES +The following command decompiles given mobi document. The output folder will be created in /tmp. +.Pp +.Dl % mobitool -s -o /tmp example.mobi +.Pp +.if !'@XMLWRITER_OPT@'yes' .ig +The following command converts mobi document to epub format. +.Pp +.Dl % mobitool -e example.mobi +.. +.Sh RETURN VALUES +The +.Nm mobitool +utility returns 0 on success, 1 on error. +.Sh COPYRIGHT +Copyright (C) 2014-2022 Bartek Fabiszewski. +.Pp +Released under LGPL version 3 or any later (same as +.Nm libmobi Ns +). +.Sh WEB SITE +Visit http://www.fabiszewski.net for details. +.Sh DIAGNOSTICS +For diagnostics +.Nm libmobi +must be configured with +.Fl Fl enable-debug +option. +.Sh SEE ALSO +.Xr mobimeta 1 +.Xr mobidrm 1 diff --git a/Charcoal/Charcoal/libmobi-public/src/mobitool.c b/Charcoal/Charcoal/libmobi-public/src/mobitool.c new file mode 100644 index 0000000..471b522 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/mobitool.c @@ -0,0 +1,1071 @@ +/** @file mobitool.c + * + * @brief mobitool + * + * @example mobitool.c + * Program for testing libmobi library + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include +/* include libmobi header */ +#include +#include "common.h" + +/* miniz file is needed for EPUB creation */ +#ifdef USE_XMLWRITER +# define MINIZ_HEADER_FILE_ONLY +# define MINIZ_NO_ZLIB_COMPATIBLE_NAMES +# include "../src/miniz.c" +#endif + +#ifdef HAVE_SYS_RESOURCE_H +/* rusage */ +# include +# define PRINT_RUSAGE_ARG "u" +#else +# define PRINT_RUSAGE_ARG "" +#endif +/* encryption */ +#ifdef USE_ENCRYPTION +# define PRINT_ENC_USG " [-p pid] [-P serial]" +# define PRINT_ENC_ARG "p:P:" +#else +# define PRINT_ENC_USG "" +# define PRINT_ENC_ARG "" +#endif +/* xmlwriter */ +#ifdef USE_XMLWRITER +# define PRINT_EPUB_ARG "e" +#else +# define PRINT_EPUB_ARG "" +#endif + +#if HAVE_ATTRIBUTE_NORETURN +static void exit_with_usage(const char *progname) __attribute__((noreturn)); +#else +static void exit_with_usage(const char *progname); +#endif + +#define EPUB_CONTAINER "\n\ +\n\ + \n\ + \n\ + \n\ +" +#define EPUB_MIMETYPE "application/epub+zip" + +/* command line options */ +bool dump_cover_opt = false; +bool dump_rawml_opt = false; +bool create_epub_opt = false; +bool print_extended_meta_opt = false; +bool print_rec_meta_opt = false; +bool dump_rec_opt = false; +bool parse_kf7_opt = false; +bool dump_parts_opt = false; +bool print_rusage_opt = false; +bool extract_source_opt = false; +bool split_opt = false; +#ifdef USE_ENCRYPTION +bool setpid_opt = false; +bool setserial_opt = false; +#endif + +/* options values */ +#ifdef USE_ENCRYPTION +char *pid = NULL; +char *serial = NULL; +#endif + +/** + @brief Print all loaded headers meta information + @param[in] m MOBIData structure + */ +static void print_meta(const MOBIData *m) { + /* Full name stored at offset given in MOBI header */ + if (m->mh && m->mh->full_name) { + char full_name[FULLNAME_MAX + 1]; + if (mobi_get_fullname(m, full_name, FULLNAME_MAX) == MOBI_SUCCESS) { + printf("\nFull name: %s\n", full_name); + } + } + /* Palm database header */ + if (m->ph) { + printf("\nPalm doc header:\n"); + printf("name: %s\n", m->ph->name); + printf("attributes: %hu\n", m->ph->attributes); + printf("version: %hu\n", m->ph->version); + struct tm * timeinfo = mobi_pdbtime_to_time(m->ph->ctime); + printf("ctime: %s", asctime(timeinfo)); + timeinfo = mobi_pdbtime_to_time(m->ph->mtime); + printf("mtime: %s", asctime(timeinfo)); + timeinfo = mobi_pdbtime_to_time(m->ph->btime); + printf("btime: %s", asctime(timeinfo)); + printf("mod_num: %u\n", m->ph->mod_num); + printf("appinfo_offset: %u\n", m->ph->appinfo_offset); + printf("sortinfo_offset: %u\n", m->ph->sortinfo_offset); + printf("type: %s\n", m->ph->type); + printf("creator: %s\n", m->ph->creator); + printf("uid: %u\n", m->ph->uid); + printf("next_rec: %u\n", m->ph->next_rec); + printf("rec_count: %u\n", m->ph->rec_count); + } + /* Record 0 header */ + if (m->rh) { + printf("\nRecord 0 header:\n"); + printf("compression type: %u\n", m->rh->compression_type); + printf("text length: %u\n", m->rh->text_length); + printf("text record count: %u\n", m->rh->text_record_count); + printf("text record size: %u\n", m->rh->text_record_size); + printf("encryption type: %u\n", m->rh->encryption_type); + printf("unknown: %u\n", m->rh->unknown1); + } + /* Mobi header */ + if (m->mh) { + printf("\nMOBI header:\n"); + printf("identifier: %s\n", m->mh->mobi_magic); + if (m->mh->header_length) { printf("header length: %u\n", *m->mh->header_length); } + if (m->mh->mobi_type) { printf("mobi type: %u\n", *m->mh->mobi_type); } + if (m->mh->text_encoding) { printf("text encoding: %u\n", *m->mh->text_encoding); } + if (m->mh->uid) { printf("unique id: %u\n", *m->mh->uid); } + if (m->mh->version) { printf("file version: %u\n", *m->mh->version); } + if (m->mh->orth_index) { printf("orth index: %u\n", *m->mh->orth_index); } + if (m->mh->infl_index) { printf("infl index: %u\n", *m->mh->infl_index); } + if (m->mh->names_index) { printf("names index: %u\n", *m->mh->names_index); } + if (m->mh->keys_index) { printf("keys index: %u\n", *m->mh->keys_index); } + if (m->mh->extra0_index) { printf("extra0 index: %u\n", *m->mh->extra0_index); } + if (m->mh->extra1_index) { printf("extra1 index: %u\n", *m->mh->extra1_index); } + if (m->mh->extra2_index) { printf("extra2 index: %u\n", *m->mh->extra2_index); } + if (m->mh->extra3_index) { printf("extra3 index: %u\n", *m->mh->extra3_index); } + if (m->mh->extra4_index) { printf("extra4 index: %u\n", *m->mh->extra4_index); } + if (m->mh->extra5_index) { printf("extra5 index: %u\n", *m->mh->extra5_index); } + if (m->mh->non_text_index) { printf("non text index: %u\n", *m->mh->non_text_index); } + if (m->mh->full_name_offset) { printf("full name offset: %u\n", *m->mh->full_name_offset); } + if (m->mh->full_name_length) { printf("full name length: %u\n", *m->mh->full_name_length); } + if (m->mh->locale) { + const char *locale_string = mobi_get_locale_string(*m->mh->locale); + if (locale_string) { + printf("locale: %s (%u)\n", locale_string, *m->mh->locale); + } else { + printf("locale: unknown (%u)\n", *m->mh->locale); + } + } + if (m->mh->dict_input_lang) { + const char *locale_string = mobi_get_locale_string(*m->mh->dict_input_lang); + if (locale_string) { + printf("dict input lang: %s (%u)\n", locale_string, *m->mh->dict_input_lang); + } else { + printf("dict input lang: unknown (%u)\n", *m->mh->dict_input_lang); + } + } + if (m->mh->dict_output_lang) { + const char *locale_string = mobi_get_locale_string(*m->mh->dict_output_lang); + if (locale_string) { + printf("dict output lang: %s (%u)\n", locale_string, *m->mh->dict_output_lang); + } else { + printf("dict output lang: unknown (%u)\n", *m->mh->dict_output_lang); + } + } + if (m->mh->min_version) { printf("minimal version: %u\n", *m->mh->min_version); } + if (m->mh->image_index) { printf("first image index: %u\n", *m->mh->image_index); } + if (m->mh->huff_rec_index) { printf("huffman record offset: %u\n", *m->mh->huff_rec_index); } + if (m->mh->huff_rec_count) { printf("huffman records count: %u\n", *m->mh->huff_rec_count); } + if (m->mh->datp_rec_index) { printf("DATP record offset: %u\n", *m->mh->datp_rec_index); } + if (m->mh->datp_rec_count) { printf("DATP records count: %u\n", *m->mh->datp_rec_count); } + if (m->mh->exth_flags) { printf("EXTH flags: %u\n", *m->mh->exth_flags); } + if (m->mh->unknown6) { printf("unknown: %u\n", *m->mh->unknown6); } + if (m->mh->drm_offset) { printf("drm offset: %u\n", *m->mh->drm_offset); } + if (m->mh->drm_count) { printf("drm count: %u\n", *m->mh->drm_count); } + if (m->mh->drm_size) { printf("drm size: %u\n", *m->mh->drm_size); } + if (m->mh->drm_flags) { printf("drm flags: %u\n", *m->mh->drm_flags); } + if (m->mh->first_text_index) { printf("first text index: %u\n", *m->mh->first_text_index); } + if (m->mh->last_text_index) { printf("last text index: %u\n", *m->mh->last_text_index); } + if (m->mh->fdst_index) { printf("FDST offset: %u\n", *m->mh->fdst_index); } + if (m->mh->fdst_section_count) { printf("FDST count: %u\n", *m->mh->fdst_section_count); } + if (m->mh->fcis_index) { printf("FCIS index: %u\n", *m->mh->fcis_index); } + if (m->mh->fcis_count) { printf("FCIS count: %u\n", *m->mh->fcis_count); } + if (m->mh->flis_index) { printf("FLIS index: %u\n", *m->mh->flis_index); } + if (m->mh->flis_count) { printf("FLIS count: %u\n", *m->mh->flis_count); } + if (m->mh->unknown10) { printf("unknown: %u\n", *m->mh->unknown10); } + if (m->mh->unknown11) { printf("unknown: %u\n", *m->mh->unknown11); } + if (m->mh->srcs_index) { printf("SRCS index: %u\n", *m->mh->srcs_index); } + if (m->mh->srcs_count) { printf("SRCS count: %u\n", *m->mh->srcs_count); } + if (m->mh->unknown12) { printf("unknown: %u\n", *m->mh->unknown12); } + if (m->mh->unknown13) { printf("unknown: %u\n", *m->mh->unknown13); } + if (m->mh->extra_flags) { printf("extra record flags: %u\n", *m->mh->extra_flags); } + if (m->mh->ncx_index) { printf("NCX offset: %u\n", *m->mh->ncx_index); } + if (m->mh->unknown14) { printf("unknown: %u\n", *m->mh->unknown14); } + if (m->mh->unknown15) { printf("unknown: %u\n", *m->mh->unknown15); } + if (m->mh->fragment_index) { printf("fragment index: %u\n", *m->mh->fragment_index); } + if (m->mh->skeleton_index) { printf("skeleton index: %u\n", *m->mh->skeleton_index); } + if (m->mh->datp_index) { printf("DATP index: %u\n", *m->mh->datp_index); } + if (m->mh->unknown16) { printf("unknown: %u\n", *m->mh->unknown16); } + if (m->mh->guide_index) { printf("guide index: %u\n", *m->mh->guide_index); } + if (m->mh->unknown17) { printf("unknown: %u\n", *m->mh->unknown17); } + if (m->mh->unknown18) { printf("unknown: %u\n", *m->mh->unknown18); } + if (m->mh->unknown19) { printf("unknown: %u\n", *m->mh->unknown19); } + if (m->mh->unknown20) { printf("unknown: %u\n", *m->mh->unknown20); } + } +} + +/** + @brief Print meta data of each document record + @param[in] m MOBIData structure + */ +static void print_records_meta(const MOBIData *m) { + /* Linked list of MOBIPdbRecord structures holds records data and metadata */ + const MOBIPdbRecord *currec = m->rec; + while (currec != NULL) { + printf("offset: %u\n", currec->offset); + printf("size: %zu\n", currec->size); + printf("attributes: %hhu\n", currec->attributes); + printf("uid: %u\n", currec->uid); + printf("\n"); + currec = currec->next; + } +} + +/** + @brief Create new path. Name is derived from input file path. + [dirname]/[basename][suffix] + @param[out] newpath Created path + @param[in] buf_len Created path buffer size + @param[in] fullpath Input file path + @param[in] suffix Path name suffix + @return SUCCESS or ERROR + */ +static int create_path(char *newpath, const size_t buf_len, const char *fullpath, const char *suffix) { + char dirname[FILENAME_MAX]; + char basename[FILENAME_MAX]; + split_fullpath(fullpath, dirname, basename, FILENAME_MAX); + int n; + if (outdir_opt) { + n = snprintf(newpath, buf_len, "%s%s%s", outdir, basename, suffix); + } else { + n = snprintf(newpath, buf_len, "%s%s%s", dirname, basename, suffix); + } + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= buf_len) { + printf("File name too long\n"); + return ERROR; + } + return SUCCESS; +} + +/** + @brief Create directory. Path is derived from input file path. + [dirname]/[basename][suffix] + @param[out] newdir Created directory path + @param[in] buf_len Created directory buffer size + @param[in] fullpath Input file path + @param[in] suffix Directory name suffix + @return SUCCESS or ERROR + */ +static int create_dir(char *newdir, const size_t buf_len, const char *fullpath, const char *suffix) { + if (create_path(newdir, buf_len, fullpath, suffix) == ERROR) { + return ERROR; + } + return make_directory(newdir); +} + +/** + @brief Dump each document record to a file into created folder + @param[in] m MOBIData structure + @param[in] fullpath File path will be parsed to build basenames of dumped records + @return SUCCESS or ERROR + */ +static int dump_records(const MOBIData *m, const char *fullpath) { + char newdir[FILENAME_MAX]; + if (create_dir(newdir, sizeof(newdir), fullpath, "_records") == ERROR) { + return ERROR; + } + printf("Saving records to %s\n", newdir); + /* Linked list of MOBIPdbRecord structures holds records data and metadata */ + const MOBIPdbRecord *currec = m->rec; + int i = 0; + while (currec != NULL) { + char name[FILENAME_MAX]; + snprintf(name, sizeof(name), "record_%i_uid_%i", i++, currec->uid); + if (write_to_dir(newdir, name, currec->data, currec->size) == ERROR) { + return ERROR; + } + + currec = currec->next; + } + return SUCCESS; +} + +/** + @brief Dump all text records, decompressed and concatenated, to a single rawml file + @param[in] m MOBIData structure + @param[in] fullpath File path will be parsed to create a new name for saved file + @return SUCCESS or ERROR + */ +static int dump_rawml(const MOBIData *m, const char *fullpath) { + char newpath[FILENAME_MAX]; + if (create_path(newpath, sizeof(newpath), fullpath, ".rawml") == ERROR) { + return ERROR; + } + printf("Saving rawml to %s\n", newpath); + errno = 0; + FILE *file = fopen(newpath, "wb"); + if (file == NULL) { + int errsv = errno; + printf("Could not open file for writing: %s (%s)\n", newpath, strerror(errsv)); + return ERROR; + } + const MOBI_RET mobi_ret = mobi_dump_rawml(m, file); + fclose(file); + if (mobi_ret != MOBI_SUCCESS) { + printf("Dumping rawml file failed (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + return SUCCESS; +} + +/** + @brief Dump cover record + @param[in] m MOBIData structure + @param[in] fullpath File path will be parsed to create a new name for saved file + @return SUCCESS or ERROR + */ +static int dump_cover(const MOBIData *m, const char *fullpath) { + + MOBIPdbRecord *record = NULL; + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_COVEROFFSET); + if (exth) { + uint32_t offset = mobi_decode_exthvalue(exth->data, exth->size); + size_t first_resource = mobi_get_first_resource_record(m); + size_t uid = first_resource + offset; + record = mobi_get_record_by_seqnumber(m, uid); + } + if (record == NULL || record->size < 4) { + printf("Cover not found\n"); + return ERROR; + } + + const unsigned char jpg_magic[] = "\xff\xd8\xff"; + const unsigned char gif_magic[] = "\x47\x49\x46\x38"; + const unsigned char png_magic[] = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; + const unsigned char bmp_magic[] = "\x42\x4d"; + + char ext[4] = "raw"; + if (memcmp(record->data, jpg_magic, 3) == 0) { + snprintf(ext, sizeof(ext), "%s", "jpg"); + } else if (memcmp(record->data, gif_magic, 4) == 0) { + snprintf(ext, sizeof(ext), "%s", "gif"); + } else if (record->size >= 8 && memcmp(record->data, png_magic, 8) == 0) { + snprintf(ext, sizeof(ext), "%s", "png"); + } else if (record->size >= 6 && memcmp(record->data, bmp_magic, 2) == 0) { + const size_t bmp_size = (uint32_t) record->data[2] | ((uint32_t) record->data[3] << 8) | + ((uint32_t) record->data[4] << 16) | ((uint32_t) record->data[5] << 24); + if (record->size == bmp_size) { + snprintf(ext, sizeof(ext), "%s", "bmp"); + } + } + + char suffix[12]; + snprintf(suffix, sizeof(suffix), "_cover.%s", ext); + + char cover_path[FILENAME_MAX]; + if (create_path(cover_path, sizeof(cover_path), fullpath, suffix) == ERROR) { + return ERROR; + } + + printf("Saving cover to %s\n", cover_path); + + return write_file(record->data, record->size, cover_path); +} + +/** + @brief Dump parsed markup files and resources into created folder + @param[in] rawml MOBIRawml structure holding parsed records + @param[in] fullpath File path will be parsed to build basenames of dumped records + @return SUCCESS or ERROR + */ +static int dump_rawml_parts(const MOBIRawml *rawml, const char *fullpath) { + if (rawml == NULL) { + printf("Rawml structure not initialized\n"); + return ERROR; + } + + char newdir[FILENAME_MAX]; + if (create_dir(newdir, sizeof(newdir), fullpath, "_markup") == ERROR) { + return ERROR; + } + printf("Saving markup to %s\n", newdir); + + if (create_epub_opt) { + /* create META_INF directory */ + char opfdir[FILENAME_MAX]; + if (create_subdir(opfdir, sizeof(opfdir), newdir, "META-INF") == ERROR) { + return ERROR; + } + + /* create container.xml */ + if (write_to_dir(opfdir, "container.xml", (const unsigned char *) EPUB_CONTAINER, sizeof(EPUB_CONTAINER) - 1) == ERROR) { + return ERROR; + } + + /* create mimetype file */ + if (write_to_dir(opfdir, "mimetype", (const unsigned char *) EPUB_MIMETYPE, sizeof(EPUB_MIMETYPE) - 1) == ERROR) { + return ERROR; + } + + /* create OEBPS directory */ + if (create_subdir(opfdir, sizeof(opfdir), newdir, "OEBPS") == ERROR) { + return ERROR; + } + + /* output everything else to OEBPS dir */ + strcpy(newdir, opfdir); + } + char partname[FILENAME_MAX]; + if (rawml->markup != NULL) { + /* Linked list of MOBIPart structures in rawml->markup holds main text files */ + MOBIPart *curr = rawml->markup; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "part%05zu.%s", curr->uid, file_meta.extension); + if (write_to_dir(newdir, partname, curr->data, curr->size) == ERROR) { + return ERROR; + } + printf("%s\n", partname); + curr = curr->next; + } + } + if (rawml->flow != NULL) { + /* Linked list of MOBIPart structures in rawml->flow holds supplementary text files */ + MOBIPart *curr = rawml->flow; + /* skip raw html file */ + curr = curr->next; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "flow%05zu.%s", curr->uid, file_meta.extension); + if (write_to_dir(newdir, partname, curr->data, curr->size) == ERROR) { + return ERROR; + } + printf("%s\n", partname); + curr = curr->next; + } + } + if (rawml->resources != NULL) { + /* Linked list of MOBIPart structures in rawml->resources holds binary files, also opf files */ + MOBIPart *curr = rawml->resources; + /* jpg, gif, png, bmp, font, audio, video also opf, ncx */ + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + if (curr->size > 0) { + int n; + if (create_epub_opt && file_meta.type == T_OPF) { + n = snprintf(partname, sizeof(partname), "%s%ccontent.opf", newdir, separator); + } else { + n = snprintf(partname, sizeof(partname), "%s%cresource%05zu.%s", newdir, separator, curr->uid, file_meta.extension); + } + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(partname)) { + printf("File name too long: %s\n", partname); + return ERROR; + } + + if (create_epub_opt && file_meta.type == T_OPF) { + printf("content.opf\n"); + } else { + printf("resource%05zu.%s\n", curr->uid, file_meta.extension); + } + + if (write_file(curr->data, curr->size, partname) == ERROR) { + return ERROR; + } + + } + curr = curr->next; + } + } + return SUCCESS; +} + +#ifdef USE_XMLWRITER +/** + @brief Bundle recreated source files into EPUB container + + This function is a simple example. + In real world implementation one should validate and correct all input + markup to check if it conforms to OPF and HTML specifications and + correct all the issues. + + @param[in] rawml MOBIRawml structure holding parsed records + @param[in] fullpath File path will be parsed to build basenames of dumped records + @return SUCCESS or ERROR + */ +static int create_epub(const MOBIRawml *rawml, const char *fullpath) { + if (rawml == NULL) { + printf("Rawml structure not initialized\n"); + return ERROR; + } + + char zipfile[FILENAME_MAX]; + if (create_path(zipfile, sizeof(zipfile), fullpath, ".epub") == ERROR) { + return ERROR; + } + printf("Saving EPUB to %s\n", zipfile); + + /* create zip (epub) archive */ + mz_zip_archive zip; + memset(&zip, 0, sizeof(mz_zip_archive)); + mz_bool mz_ret = mz_zip_writer_init_file(&zip, zipfile, 0); + if (!mz_ret) { + printf("Could not initialize zip archive\n"); + return ERROR; + } + /* start adding files to archive */ + mz_ret = mz_zip_writer_add_mem(&zip, "mimetype", EPUB_MIMETYPE, sizeof(EPUB_MIMETYPE) - 1, MZ_NO_COMPRESSION); + if (!mz_ret) { + printf("Could not add mimetype\n"); + mz_zip_writer_end(&zip); + return ERROR; + } + mz_ret = mz_zip_writer_add_mem(&zip, "META-INF/container.xml", EPUB_CONTAINER, sizeof(EPUB_CONTAINER) - 1, (mz_uint)MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add container.xml\n"); + mz_zip_writer_end(&zip); + return ERROR; + } + char partname[FILENAME_MAX]; + if (rawml->markup != NULL) { + /* Linked list of MOBIPart structures in rawml->markup holds main text files */ + MOBIPart *curr = rawml->markup; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "OEBPS/part%05zu.%s", curr->uid, file_meta.extension); + mz_ret = mz_zip_writer_add_mem(&zip, partname, curr->data, curr->size, (mz_uint) MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add file to archive: %s\n", partname); + mz_zip_writer_end(&zip); + return ERROR; + } + curr = curr->next; + } + } + if (rawml->flow != NULL) { + /* Linked list of MOBIPart structures in rawml->flow holds supplementary text files */ + MOBIPart *curr = rawml->flow; + /* skip raw html file */ + curr = curr->next; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "OEBPS/flow%05zu.%s", curr->uid, file_meta.extension); + mz_ret = mz_zip_writer_add_mem(&zip, partname, curr->data, curr->size, (mz_uint) MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add file to archive: %s\n", partname); + mz_zip_writer_end(&zip); + return ERROR; + } + curr = curr->next; + } + } + if (rawml->resources != NULL) { + /* Linked list of MOBIPart structures in rawml->resources holds binary files, also opf files */ + MOBIPart *curr = rawml->resources; + /* jpg, gif, png, bmp, font, audio, video, also opf, ncx */ + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + if (curr->size > 0) { + if (file_meta.type == T_OPF) { + snprintf(partname, sizeof(partname), "OEBPS/content.opf"); + } else { + snprintf(partname, sizeof(partname), "OEBPS/resource%05zu.%s", curr->uid, file_meta.extension); + } + mz_ret = mz_zip_writer_add_mem(&zip, partname, curr->data, curr->size, (mz_uint) MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add file to archive: %s\n", partname); + mz_zip_writer_end(&zip); + return ERROR; + } + } + curr = curr->next; + } + } + /* Finalize epub archive */ + mz_ret = mz_zip_writer_finalize_archive(&zip); + if (!mz_ret) { + printf("Could not finalize zip archive\n"); + mz_zip_writer_end(&zip); + return ERROR; + } + mz_ret = mz_zip_writer_end(&zip); + if (!mz_ret) { + printf("Could not finalize zip writer\n"); + return ERROR; + } + return SUCCESS; +} +#endif + +/** + @brief Dump SRCS record + @param[in] m MOBIData structure + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int dump_embedded_source(const MOBIData *m, const char *fullpath) { + /* Try to get embedded source */ + unsigned char *data = NULL; + size_t size = 0; + MOBI_RET mobi_ret = mobi_get_embedded_source(&data, &size, m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Extracting source from mobi failed (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + if (data == NULL || size == 0 ) { + printf("Source archive not found\n"); + return SUCCESS; + } + + char newdir[FILENAME_MAX]; + if (create_dir(newdir, sizeof(newdir), fullpath, "_source") == ERROR) { + return ERROR; + } + + const unsigned char epub_magic[] = "mimetypeapplication/epub+zip"; + const size_t em_offset = 30; + const size_t em_size = sizeof(epub_magic) - 1; + const char *ext; + if (size > em_offset + em_size && memcmp(data + em_offset, epub_magic, em_size) == 0) { + ext = "epub"; + } else { + ext = "zip"; + } + + char srcsname[FILENAME_MAX]; + char basename[FILENAME_MAX]; + split_fullpath(fullpath, NULL, basename, FILENAME_MAX); + int n = snprintf(srcsname, sizeof(srcsname), "%s_source.%s", basename, ext); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(srcsname)) { + printf("File name too long\n"); + return ERROR; + } + if (write_to_dir(newdir, srcsname, data, size) == ERROR) { + return ERROR; + } + printf("Saving source archive to %s\n", srcsname); + + /* Try to get embedded conversion log */ + data = NULL; + size = 0; + mobi_ret = mobi_get_embedded_log(&data, &size, m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Extracting conversion log from mobi failed (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + if (data == NULL || size == 0 ) { + printf("Conversion log not found\n"); + return SUCCESS; + } + + n = snprintf(srcsname, sizeof(srcsname), "%s_source.txt", basename); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(srcsname)) { + printf("File name too long\n"); + return ERROR; + } + if (write_to_dir(newdir, srcsname, data, size) == ERROR) { + return ERROR; + } + printf("Saving conversion log to %s\n", srcsname); + + return SUCCESS; +} + +/** + @brief Split hybrid file in two parts + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int split_hybrid(const char *fullpath) { + + static int run_count = 0; + run_count++; + + bool use_kf8 = run_count == 1 ? false : true; + + /* Initialize main MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Memory allocation failed\n"); + return ERROR; + } + + errno = 0; + FILE *file = fopen(fullpath, "rb"); + if (file == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", fullpath, strerror(errsv)); + mobi_free(m); + return ERROR; + } + /* MOBIData structure will be filled with loaded document data and metadata */ + MOBI_RET mobi_ret = mobi_load_file(m, file); + fclose(file); + + if (mobi_ret != MOBI_SUCCESS) { + printf("Error while loading document (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + mobi_ret = mobi_remove_hybrid_part(m, use_kf8); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error removing hybrid part (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + if (save_mobi(m, fullpath, "split") != SUCCESS) { + printf("Error saving file\n"); + mobi_free(m); + return ERROR; + } + + /* Free MOBIData structure */ + mobi_free(m); + + /* Proceed with KF8 part */ + if (use_kf8 == false) { + split_hybrid(fullpath); + } + + return SUCCESS; +} + +/** + @brief Main routine that calls optional subroutines + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int loadfilename(const char *fullpath) { + MOBI_RET mobi_ret; + int ret = SUCCESS; + /* Initialize main MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Memory allocation failed\n"); + return ERROR; + } + /* By default loader will parse KF8 part of hybrid KF7/KF8 file */ + if (parse_kf7_opt) { + /* Force it to parse KF7 part */ + mobi_parse_kf7(m); + } + errno = 0; + FILE *file = fopen(fullpath, "rb"); + if (file == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", fullpath, strerror(errsv)); + mobi_free(m); + return ERROR; + } + /* MOBIData structure will be filled with loaded document data and metadata */ + mobi_ret = mobi_load_file(m, file); + fclose(file); + + /* Try to print basic metadata, even if further loading failed */ + /* In case of some unsupported formats it may still print some useful info */ + if (print_extended_meta_opt) { print_meta(m); } + + if (mobi_ret != MOBI_SUCCESS) { + printf("Error while loading document (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + if (create_epub_opt && mobi_is_replica(m)) { + create_epub_opt = false; + printf("\nWarning: Can't create EPUB format from Print Replica book (ignoring -e argument)\n\n"); + } + + if (!print_extended_meta_opt) { + print_summary(m); + } + + if (print_extended_meta_opt) { + /* Try to print EXTH metadata */ + print_exth(m); + } + +#ifdef USE_ENCRYPTION + if (setpid_opt || setserial_opt) { + ret = set_decryption_key(m, serial, pid); + if (ret != SUCCESS) { + mobi_free(m); + return ret; + } + } +#endif + if (print_rec_meta_opt) { + printf("\nPrinting records metadata...\n"); + print_records_meta(m); + } + if (dump_rec_opt) { + printf("\nDumping raw records...\n"); + ret = dump_records(m, fullpath); + } + if (dump_rawml_opt) { + printf("\nDumping rawml...\n"); + ret = dump_rawml(m, fullpath); + } else if (dump_parts_opt || create_epub_opt) { + printf("\nReconstructing source resources...\n"); + /* Initialize MOBIRawml structure */ + /* This structure will be filled with parsed records data */ + MOBIRawml *rawml = mobi_init_rawml(m); + if (rawml == NULL) { + printf("Memory allocation failed\n"); + mobi_free(m); + return ERROR; + } + + /* Parse rawml text and other data held in MOBIData structure into MOBIRawml structure */ + mobi_ret = mobi_parse_rawml(rawml, m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Parsing rawml failed (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + mobi_free_rawml(rawml); + return ERROR; + } + if (create_epub_opt && !dump_parts_opt) { +#ifdef USE_XMLWRITER + printf("\nCreating EPUB...\n"); + /* Create epub file */ + ret = create_epub(rawml, fullpath); + if (ret != SUCCESS) { + printf("Creating EPUB failed\n"); + } +#endif + } else { + printf("\nDumping resources...\n"); + /* Save parts to files */ + ret = dump_rawml_parts(rawml, fullpath); + if (ret != SUCCESS) { + printf("Dumping parts failed\n"); + } + } + /* Free MOBIRawml structure */ + mobi_free_rawml(rawml); + } + if (extract_source_opt) { + ret = dump_embedded_source(m, fullpath); + } + if (dump_cover_opt) { + ret = dump_cover(m, fullpath); + } + if (split_opt && !mobi_is_hybrid(m)) { + printf("File is not a hybrid, skip splitting\n"); + split_opt = false; + } + /* Free MOBIData structure */ + mobi_free(m); + return ret; +} + +/** + @brief Print usage info + @param[in] progname Executed program name + */ +static void exit_with_usage(const char *progname) { + printf("usage: %s [-cd" PRINT_EPUB_ARG "himrst" PRINT_RUSAGE_ARG "vx7] [-o dir]" PRINT_ENC_USG " filename\n", progname); + printf(" without arguments prints document metadata and exits\n"); + printf(" -c dump cover\n"); + printf(" -d dump rawml text record\n"); +#ifdef USE_XMLWRITER + printf(" -e create EPUB file (with -s will dump EPUB source)\n"); +#endif + printf(" -h show this usage summary and exit\n"); + printf(" -i print detailed metadata\n"); + printf(" -m print records metadata\n"); + printf(" -o dir save output to dir folder\n"); +#ifdef USE_ENCRYPTION + printf(" -p pid set pid for decryption\n"); + printf(" -P serial set device serial for decryption\n"); +#endif + printf(" -r dump raw records\n"); + printf(" -s dump recreated source files\n"); + printf(" -t split hybrid file into two parts\n"); +#ifdef HAVE_SYS_RESOURCE_H + printf(" -u show rusage\n"); +#endif + printf(" -v show version and exit\n"); + printf(" -x extract conversion source and log (if present)\n"); + printf(" -7 parse KF7 part of hybrid file (by default KF8 part is parsed)\n"); + exit(SUCCESS); +} + +/** + @brief Main + + @param[in] argc Arguments count + @param[in] argv Arguments array + @return SUCCESS (0) or ERROR (1) + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + exit_with_usage(argv[0]); + } + opterr = 0; + int c; + while ((c = getopt(argc, argv, "cd" PRINT_EPUB_ARG "himo:" PRINT_ENC_ARG "rst" PRINT_RUSAGE_ARG "vx7")) != -1) { + switch (c) { + case 'c': + dump_cover_opt = true; + break; + case 'd': + dump_rawml_opt = true; + break; +#ifdef USE_XMLWRITER + case 'e': + create_epub_opt = true; + break; +#endif + case 'i': + print_extended_meta_opt = true; + break; + case 'm': + print_rec_meta_opt = true; + break; + case 'o': + outdir_opt = true; + size_t outdir_length = strlen(optarg); + if (outdir_length == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + if (outdir_length >= FILENAME_MAX - 1) { + printf("Output directory name too long\n"); + return ERROR; + } + strncpy(outdir, optarg, FILENAME_MAX - 1); + normalize_path(outdir); + if (!dir_exists(outdir)) { + printf("Output directory is not valid\n"); + return ERROR; + } + if (optarg[outdir_length - 1] != separator) { + // append separator + if (outdir_length >= FILENAME_MAX - 2) { + printf("Output directory name too long\n"); + return ERROR; + } + outdir[outdir_length++] = separator; + outdir[outdir_length] = '\0'; + } + break; +#ifdef USE_ENCRYPTION + case 'p': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + setpid_opt = true; + pid = optarg; + break; + case 'P': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + setserial_opt = true; + serial = optarg; + break; +#endif + case 'r': + dump_rec_opt = true; + break; + case 's': + dump_parts_opt = true; + break; + case 't': + split_opt = true; + break; +#ifdef HAVE_SYS_RESOURCE_H + case 'u': + print_rusage_opt = true; + break; +#endif + case 'v': + printf("mobitool build: " __DATE__ " " __TIME__ " (" COMPILER ")\n"); + printf("libmobi: %s\n", mobi_version()); + return SUCCESS; + case 'x': + extract_source_opt = true; + break; + case '7': + parse_kf7_opt = true; + break; + case '?': + if (isprint(optopt)) { + fprintf(stderr, "Unknown option `-%c'\n", optopt); + } + else { + fprintf(stderr, "Unknown option character `\\x%x'\n", optopt); + } + exit_with_usage(argv[0]); + case 'h': + default: + exit_with_usage(argv[0]); + } + } + if (argc <= optind) { + printf("Missing filename\n"); + exit_with_usage(argv[0]); + } + + int ret = SUCCESS; + char filename[FILENAME_MAX]; + strncpy(filename, argv[optind], FILENAME_MAX - 1); + filename[FILENAME_MAX - 1] = '\0'; + normalize_path(filename); + + ret = loadfilename(filename); + if (split_opt) { + printf("\nSplitting hybrid file...\n"); + ret = split_hybrid(filename); + } +#ifdef HAVE_SYS_RESOURCE_H + if (print_rusage_opt) { + /* rusage */ + struct rusage ru; + struct timeval utime; + struct timeval stime; + getrusage(RUSAGE_SELF, &ru); + utime = ru.ru_utime; + stime = ru.ru_stime; + printf("RUSAGE: ru_utime => %lld.%lld sec.; ru_stime => %lld.%lld sec.\n", + (long long) utime.tv_sec, (long long) utime.tv_usec, + (long long) stime.tv_sec, (long long) stime.tv_usec); + } +#endif + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/opf.c b/Charcoal/Charcoal/libmobi-public/src/opf.c new file mode 100644 index 0000000..35262bb --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/opf.c @@ -0,0 +1,2059 @@ +/** @file opf.c + * @brief Functions for handling OPF structures + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#define _GNU_SOURCE 1 +#ifndef __USE_BSD +#define __USE_BSD /* for strdup on linux/glibc */ +#endif + +#include +#include +#include "opf.h" +#ifdef USE_LIBXML2 +#ifdef __clang__ +#pragma clang diagnostic push +/* suppress clang documentation warning for libxml headers */ +#pragma clang diagnostic ignored "-Wdocumentation" +#endif +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#else +#include "xmlwriter.h" +#endif +#include "index.h" +#include "util.h" +#include "parse_rawml.h" +#include "debug.h" + +/** + @brief Array of valid OPF guide types + + http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.6 + */ +const char *mobi_guide_types[] = { + "cover", /**< the book cover(s), jacket information, etc. */ + "title-page", /**< page with possibly title, author, publisher, and other metadata */ + "toc", /**< table of contents */ + "index", /**< back-of-book style index */ + "glossary", /**< glossary */ + "acknowledgements", /**< acknowledgements */ + "bibliography", /**< bibliography */ + "colophon", /**< colophon */ + "copyright-page", /**< copyright page */ + "dedication", /**< dedication */ + "epigraph", /**< epigraph */ + "foreword", /**< foreword */ + "loi", /**< list of illustrations */ + "lot", /**< list of tables */ + "notes", /**< notes */ + "preface", /**< preface */ + "text", /**< First "real" page of content (e.g. "Chapter 1") */ + NULL /**< eof */ +}; + +/** + @brief Check if type is valid OPF guide element + + Compares types with elements of mobi_guide_types[] array + + @param[in] type OPF guide type + @return True if type is valid guide type, false otherwise + */ +bool mobi_is_guide_type(const char *type) { + size_t i = 0; + size_t type_length = strlen(type); + while (mobi_guide_types[i]) { + if (strncmp(mobi_guide_types[i++], type, type_length) == 0) { + return true; + } + } + /* check if "other" type */ + if (strncmp(type, "other.", 6) == 0) { return true; } + return false; +} + +/** + @brief Reconstruct guide part of the OPF file + + @param[in,out] opf Structure OPF->OPFguide will be filled with parsed data + @param[in] rawml Structure MOBIRawml will be parsed + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_build_opf_guide(OPF *opf, const MOBIRawml *rawml) { + /* parse guide data */ + if (rawml == NULL || rawml->guide == NULL) { + debug_print("%s\n", "Initialization failed"); + return MOBI_INIT_FAILED; + } + size_t i = 0; + size_t j = 0; + MOBI_RET ret; + size_t count = rawml->guide->entries_count; + if (count == 0) { + return MOBI_SUCCESS; + } + if (rawml->frag == NULL) { + debug_print("%s\n", "Missing frag part"); + return MOBI_DATA_CORRUPT; + } + opf->guide = malloc(sizeof(OPFguide)); + if (opf->guide == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + OPFreference **reference = malloc((count + 1) * sizeof(OPFreference*)); + if (reference == NULL) { + free(opf->guide); + opf->guide = NULL; + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (rawml->guide->cncx_record == NULL) { + free(reference); + free(opf->guide); + opf->guide = NULL; + debug_print("%s\n", "Missing cncx record"); + return MOBI_DATA_CORRUPT; + } + while (i < count) { + const MOBIIndexEntry *guide_entry = &rawml->guide->entries[i]; + const char *type = guide_entry->label; + uint32_t cncx_offset; + ret = mobi_get_indxentry_tagvalue(&cncx_offset, guide_entry, INDX_TAG_GUIDE_TITLE_CNCX); + if (ret != MOBI_SUCCESS) { + free(reference); + free(opf->guide); + opf->guide = NULL; + return ret; + } + const MOBIPdbRecord *cncx_record = rawml->guide->cncx_record; + char *ref_title = mobi_get_cncx_string_utf8(cncx_record, cncx_offset, rawml->guide->encoding); + if (ref_title == NULL) { + free(reference); + free(opf->guide); + opf->guide = NULL; + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + uint32_t frag_number = MOBI_NOTSET; + ret = mobi_get_indxentry_tagvalue(&frag_number, guide_entry, INDX_TAG_FRAG_POSITION); + if (ret != MOBI_SUCCESS) { + debug_print("INDX_TAG_FRAG_POSITION not found (%i)\n", ret); + free(ref_title); + i++; + continue; + /* FIXME: I need some examples which use other tags */ + //mobi_get_indxentry_tagvalue(&frag_number, guide_entry, INDX_TAG_FRAG_FILE_NR); + } + if (frag_number >= rawml->frag->entries_count) { + debug_print("Wrong frag entry index (%i)\n", frag_number); + free(ref_title); + i++; + continue; + } + const MOBIIndexEntry *frag_entry = &rawml->frag->entries[frag_number]; + uint32_t file_number; + ret = mobi_get_indxentry_tagvalue(&file_number, frag_entry, INDX_TAG_FRAG_FILE_NR); + if (ret != MOBI_SUCCESS) { + free(reference); + free(opf->guide); + free(ref_title); + opf->guide = NULL; + return ret; + } + /* check if valid guide type */ + char *ref_type; + size_t type_size = strlen(type); + if (!mobi_is_guide_type(type)) { + /* prepend "other." prefix */ + type_size += 6; + ref_type = malloc(type_size + 1); + if (ref_type == NULL) { + free(reference); + free(opf->guide); + opf->guide = NULL; + free(ref_title); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + snprintf(ref_type, type_size + 1, "other.%s", type); + } else { + ref_type = malloc(type_size + 1); + if (ref_type == NULL) { + free(reference); + free(opf->guide); + opf->guide = NULL; + free(ref_title); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + memcpy(ref_type, type, type_size); + ref_type[type_size] = '\0'; + } + debug_print("", ref_type, ref_title, file_number); + char href[FILENAME_MAX + 1]; + snprintf(href, sizeof(href), "part%05u.html", file_number); + char *ref_href = strdup(href); + reference[j] = calloc(1, sizeof(OPFreference)); + *reference[j] = (OPFreference) { ref_type, ref_title, ref_href }; + i++; + j++; + } + /* terminate array with NULL */ + reference[j] = NULL; + opf->guide->reference = reference; + return MOBI_SUCCESS; +} + +/** + @brief Write entries for given ncx level + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] ncx Array of NCX structures with ncx content + @param[in] level TOC level + @param[in] from First entry in NCX array to copy from + @param[in] to Last entry in NCX array to copy from + @param[in] seq Sequential number for playOrder attribute + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_write_ncx_level(xmlTextWriterPtr writer, const NCX *ncx, const size_t level, const size_t from, const size_t to, size_t *seq) { + for (size_t i = from; i <= to; i++) { + if (level != ncx[i].level) { + continue; + } + /* start */ + char playorder[10 + 1]; + snprintf(playorder, 11, "%u", (uint32_t) (*seq)++); + + /* id string (max 10 digits and dash) for each level + "toc" + terminator */ + size_t id_size = 11 * (level + 1) + 3 + 1; + char *id = malloc(id_size); + if (id == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + strcpy(id, "toc"); + size_t curr_id = i; + while (curr_id != MOBI_NOTSET) { + size_t parent_id = ncx[curr_id].parent; + if (parent_id == curr_id) { + debug_print("%s\n", "Skip id of corrupt ncx entry"); + break; + } + size_t curr_from = 0; + if (parent_id != MOBI_NOTSET && ncx[parent_id].first_child != MOBI_NOTSET) { + curr_from = ncx[parent_id].first_child; + } + char level_id[10 + 1]; + snprintf(level_id, 11, "%u", (uint32_t) (curr_id - curr_from + 1)); + char *id_copy = strdup(id + 3); + if (id_copy == NULL) { + debug_print("%s\n", "Memory allocation failed"); + free(id); + return MOBI_MALLOC_FAILED; + } + snprintf(id, id_size, "toc-%s%s", level_id, id_copy); + free(id_copy); + curr_id = parent_id; + } + + int xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "navPoint"); + if (xml_ret < 0) { + free(id); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST id); + free(id); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "playOrder", BAD_CAST playorder); + if (xml_ret < 0) { return MOBI_XML_ERR; } + /* write */ + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "navLabel"); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "text"); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST ncx[i].text); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + /* write */ + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "content"); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "src", BAD_CAST ncx[i].target); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + debug_print("%s - %s\n", ncx[i].text, ncx[i].target); + if (ncx[i].first_child != MOBI_NOTSET && ncx[i].last_child != MOBI_NOTSET) { + MOBI_RET ret = mobi_write_ncx_level(writer, ncx, level + 1, ncx[i].first_child, ncx[i].last_child, seq); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + /* end */ + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + } + return MOBI_SUCCESS; +} + +/** + @brief Write element to XML buffer + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] name Attribute name + @param[in] content Attribute content + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_meta(xmlTextWriterPtr writer, const char *name, const char *content) { + int xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "meta"); + if (xml_ret < 0) { + debug_print("XML error: %i (name: %s, content: %s)\n", xml_ret, name, content); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name); + if (xml_ret < 0) { + debug_print("XML error: %i (name: %s, content: %s)\n", xml_ret, name, content); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "content", BAD_CAST content); + if (xml_ret < 0) { + debug_print("XML error: %i (name: %s, content: %s)\n", xml_ret, name, content); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (name: %s, content: %s)\n", xml_ret, name, content); + return MOBI_XML_ERR; + } + return MOBI_SUCCESS; +} + + +/** + @brief Add reconstruced opf part to rawml + + @param[in] opf_xml OPF xml string + @param[in,out] rawml New data will be added to MOBIRawml rawml->resources structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_opf_add_to_rawml(const char *opf_xml, MOBIRawml *rawml) { + MOBIPart *opf_part; + size_t uid = 0; + if (rawml->resources) { + MOBIPart *part = rawml->resources; + while (part->next) { + part = part->next; + } + uid = part->uid + 1; + part->next = calloc(1, sizeof(MOBIPart)); + opf_part = part->next; + } + else { + rawml->resources = calloc(1, sizeof(MOBIPart)); + opf_part = rawml->resources; + } + if (opf_part == NULL) { + return MOBI_MALLOC_FAILED; + } + opf_part->uid = uid; + opf_part->next = NULL; + opf_part->data = (unsigned char *) strdup(opf_xml); + if (opf_part->data == NULL) { + free(opf_part); + opf_part = NULL; + return MOBI_MALLOC_FAILED; + } + opf_part->size = strlen(opf_xml); + opf_part->type = T_OPF; + return MOBI_SUCCESS; +} + +/** + @brief Add reconstruced ncx part to rawml + + @param[in] ncx_xml OPF xml string + @param[in,out] rawml New data will be added to MOBIRawml rawml->resources structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_ncx_add_to_rawml(const char *ncx_xml, MOBIRawml *rawml) { + MOBIPart *ncx_part; + size_t uid = 0; + if (rawml->resources) { + MOBIPart *part = rawml->resources; + while (part->next) { + part = part->next; + } + uid = part->uid + 1; + part->next = calloc(1, sizeof(MOBIPart)); + ncx_part = part->next; + } + else { + rawml->resources = calloc(1, sizeof(MOBIPart)); + ncx_part = rawml->resources; + } + if (ncx_part == NULL) { + return MOBI_MALLOC_FAILED; + } + ncx_part->uid = uid; + ncx_part->next = NULL; + ncx_part->data = (unsigned char *) strdup(ncx_xml); + if (ncx_part->data == NULL) { + free(ncx_part); + ncx_part = NULL; + return MOBI_MALLOC_FAILED; + } + ncx_part->size = strlen(ncx_xml); + ncx_part->type = T_NCX; + return MOBI_SUCCESS; +} + +/** + @brief Write ncx header + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] opf OPF structure to fetch some data + @param[in] maxlevel Value of dtb:depth attribute + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_write_ncx_header(xmlTextWriterPtr writer, const OPF *opf, uint32_t maxlevel) { + /* write header */ + char depth[10 + 1]; + snprintf(depth, 11, "%d", maxlevel); + + /* */ + int xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "head"); + if (xml_ret < 0) { return MOBI_XML_ERR; } + /* meta uid */ + MOBI_RET ret = mobi_xml_write_meta(writer, "dtb:uid", opf->metadata->dc_meta->identifier[0]->value); + if (ret != MOBI_SUCCESS) { return ret; } + /* meta depth */ + ret = mobi_xml_write_meta(writer, "dtb:depth", depth); + if (ret != MOBI_SUCCESS) { return ret; } + /* meta pagecount */ + ret = mobi_xml_write_meta(writer, "dtb:totalPageCount", "0"); + if (ret != MOBI_SUCCESS) { return ret; } + /* meta pagenumber */ + ret = mobi_xml_write_meta(writer, "dtb:maxPageNumber", "0"); + if (ret != MOBI_SUCCESS) { return ret; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + // + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "docTitle"); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "text"); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST opf->metadata->dc_meta->title[0]); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { return MOBI_XML_ERR; } + return MOBI_SUCCESS; +} + +/** + @brief Build ncx document using libxml2 and append it to rawml + + @param[in,out] rawml MOBIRawml structure + @param[in] ncx Array of NCX structures with ncx content + @param[in] opf OPF structure to fetch some data + @param[in] maxlevel Value of dtb:depth attribute + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_write_ncx(MOBIRawml *rawml, const NCX *ncx, const OPF *opf, uint32_t maxlevel) { + const xmlChar * NCXNamespace = BAD_CAST "http://www.daisy.org/z3986/2005/ncx/"; + xmlBufferPtr buf = xmlBufferCreate(); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + xmlTextWriterPtr writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + xmlBufferFree(buf); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + xmlTextWriterSetIndent(writer, 1); + int xml_ret = xmlTextWriterStartDocument(writer, NULL, NULL, NULL); + if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "ncx", NCXNamespace); + if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "2005-1"); + if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang", BAD_CAST opf->metadata->dc_meta->language[0]); + if (xml_ret < 0) { goto cleanup; } + + MOBI_RET ret = mobi_write_ncx_header(writer, opf, maxlevel); + if (ret != MOBI_SUCCESS) { goto cleanup; } + + /* start */ + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "navMap"); + if (xml_ret < 0) { goto cleanup; } + if (ncx && rawml->ncx->entries_count > 0) { + const size_t count = rawml->ncx->entries_count; + size_t seq = 1; + ret = mobi_write_ncx_level(writer, ncx, 0, 0, count - 1, &seq); + if (ret != MOBI_SUCCESS) { goto cleanup; } + } + + /* end */ + xml_ret = xmlTextWriterEndDocument(writer); + if (xml_ret < 0) { goto cleanup; } + xmlFreeTextWriter(writer); + const char *ncx_xml = (const char *) buf->content; + mobi_ncx_add_to_rawml(ncx_xml, rawml); + xmlBufferFree(buf); + return MOBI_SUCCESS; + +cleanup: + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + debug_print("%s\n", "XML writing failed"); + return MOBI_XML_ERR; +} + + +/** + @brief Free array of ncx entries + + @param[in] ncx Array of NCX structures with ncx content + @param[in] count Size of the array + */ +void mobi_free_ncx(NCX *ncx, size_t count) { + if (ncx) { + while (count--) { + free(ncx[count].target); + free(ncx[count].text); + } + free(ncx); + } +} + +/** + @brief Parse ncx index, recreate ncx document and append it to rawml + + @param[in,out] rawml MOBIRawml structure + @param[in] opf OPF structure to fetch some data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_build_ncx(MOBIRawml *rawml, const OPF *opf) { + /* parse ncx data */ + if (rawml == NULL) { + debug_print("%s\n", "Initialization failed"); + return MOBI_INIT_FAILED; + } + if (rawml->ncx && rawml->ncx->cncx_record) { + size_t i = 0; + uint32_t maxlevel = 0; + MOBI_RET ret; + const size_t count = rawml->ncx->entries_count; + if (count == 0) { + return MOBI_SUCCESS; + } + NCX *ncx = malloc(count * sizeof(NCX)); + if (ncx == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBIAttrType pref_attr = ATTR_ID; + while (i < count) { + const MOBIIndexEntry *ncx_entry = &rawml->ncx->entries[i]; + const char *label = ncx_entry->label; + const size_t id = strtoul(label, NULL, 16); + uint32_t cncx_offset; + ret = mobi_get_indxentry_tagvalue(&cncx_offset, ncx_entry, INDX_TAG_NCX_TEXT_CNCX); + if (ret != MOBI_SUCCESS) { + mobi_free_ncx(ncx, i); + return ret; + } + const MOBIPdbRecord *cncx_record = rawml->ncx->cncx_record; + char *text = mobi_get_cncx_string_utf8(cncx_record, cncx_offset, rawml->ncx->encoding); + if (text == NULL) { + mobi_free_ncx(ncx, i); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char *target = malloc(MOBI_ATTRNAME_MAXSIZE + 1); + if (target == NULL) { + free(text); + mobi_free_ncx(ncx, i); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (mobi_is_rawml_kf8(rawml)) { + uint32_t posfid; + ret = mobi_get_indxentry_tagvalue(&posfid, ncx_entry, INDX_TAG_NCX_POSFID); + if (ret != MOBI_SUCCESS) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + uint32_t posoff; + ret = mobi_get_indxentry_tagvalue(&posoff, ncx_entry, INDX_TAG_NCX_POSOFF); + if (ret != MOBI_SUCCESS) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + uint32_t filenumber; + char targetid[MOBI_ATTRNAME_MAXSIZE + 1]; + ret = mobi_get_id_by_posoff(&filenumber, targetid, rawml, posfid, posoff, &pref_attr); + if (ret != MOBI_SUCCESS) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + /* FIXME: posoff == 0 means top of file? */ + if (posoff) { + int n = snprintf(target, MOBI_ATTRNAME_MAXSIZE + 1, "part%05u.html#%s", filenumber, targetid); + if (n > MOBI_ATTRVALUE_MAXSIZE + 1) { + debug_print("Warning: truncated target: %s\n", target); + snprintf(target, MOBI_ATTRNAME_MAXSIZE + 1, "part%05u.html", filenumber); + } + } else { + snprintf(target, MOBI_ATTRNAME_MAXSIZE + 1, "part%05u.html", filenumber); + } + + } else { + uint32_t filepos; + ret = mobi_get_indxentry_tagvalue(&filepos, ncx_entry, INDX_TAG_NCX_FILEPOS); + if (ret != MOBI_SUCCESS) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + snprintf(target, MOBI_ATTRNAME_MAXSIZE + 1, "part00000.html#%010u", filepos); + } + uint32_t level; + ret = mobi_get_indxentry_tagvalue(&level, ncx_entry, INDX_TAG_NCX_LEVEL); + if (ret != MOBI_SUCCESS) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + if (level > maxlevel) { + maxlevel = level; + } + uint32_t parent = MOBI_NOTSET; + ret = mobi_get_indxentry_tagvalue(&parent, ncx_entry, INDX_TAG_NCX_PARENT); + if (ret == MOBI_INIT_FAILED) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + uint32_t first_child = MOBI_NOTSET; + ret = mobi_get_indxentry_tagvalue(&first_child, ncx_entry, INDX_TAG_NCX_CHILD_START); + if (ret == MOBI_INIT_FAILED) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + uint32_t last_child = MOBI_NOTSET; + ret = mobi_get_indxentry_tagvalue(&last_child, ncx_entry, INDX_TAG_NCX_CHILD_END); + if (ret == MOBI_INIT_FAILED) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return ret; + } + if ((first_child != MOBI_NOTSET && first_child >= rawml->ncx->entries_count) || + (last_child != MOBI_NOTSET && last_child >= rawml->ncx->entries_count) || + (parent != MOBI_NOTSET && parent >= rawml->ncx->entries_count)) { + free(text); + free(target); + mobi_free_ncx(ncx, i); + return MOBI_DATA_CORRUPT; + } + debug_print("seq=%zu, id=%zu, text='%s', target='%s', level=%u, parent=%u, fchild=%u, lchild=%u\n", i, id, text, target, level, parent, first_child, last_child); + ncx[i++] = (NCX) {id, text, target, level, parent, first_child, last_child}; + } + mobi_write_ncx(rawml, ncx, opf, maxlevel); + mobi_free_ncx(ncx, count); + } else { + mobi_write_ncx(rawml, NULL, opf, 1); + } + return MOBI_SUCCESS; +} + +/** + @brief Copy text data from EXTH record to array of strings + + It will allocate memory for the array if not already allocated. + It will find first array index that is not already used + + @param[in] m MOBIData structure + @param[in] exth MOBIExthHeader record + @param[in,out] array Array into which text string will be inserted + */ +static void mobi_opf_fill_tag(const MOBIData *m, const MOBIExthHeader *exth, char ***array) { + if (*array == NULL) { + *array = calloc(OPF_META_MAX_TAGS, sizeof(**array)); + if (*array == NULL) { + return; + } + } + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + /* find first free slot */ + if((*array)[i] != NULL) { i++; continue; } + MOBIExthMeta exth_tag = mobi_get_exthtagmeta_by_tag(exth->tag); + char *value = NULL; + if (exth_tag.type == EXTH_NUMERIC) { + value = malloc(10 + 1); + if (value) { + const uint32_t val32 = mobi_decode_exthvalue(exth->data, exth->size); + snprintf(value, 10 + 1, "%d", val32); + } + } else if (exth_tag.type == EXTH_STRING) { + value = mobi_decode_exthstring(m, exth->data, exth->size); + } + if (value) { + (*array)[i] = value; + } + return; + } + /* not enough tags */ + debug_print("OPF_META_MAX_TAGS = %i reached\n", OPF_META_MAX_TAGS); +} + +/** + @brief Set values for attributes of OPF tag + + It will allocate memory for the OPFmeta members: name and content. + It will find first array index that is not already used + + @param[in,out] meta Array of OPFmeta structures to be filled with data + @param[in] name Value of the name attribute + @param[in] content Value of the content attribute + */ +static void mobi_opf_set_meta(OPFmeta **meta, const char *name, const char *content) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + /* find first free slot */ + if(meta[i] != NULL) { i++; continue; } + meta[i] = malloc(sizeof(OPFmeta)); + if (meta[i] == NULL) { + return; + } + meta[i]->name = strdup(name); + meta[i]->content = strdup(content); + if (meta[i]->name == NULL || meta[i]->content == NULL) { + free(meta[i]); + meta[i] = NULL; + } + return; + } + /* not enough tags */ + debug_print("OPF_META_MAX_TAGS = %i reached\n", OPF_META_MAX_TAGS); +} + +/** + @brief Set values for attributes of OPF tag + + It will allocate memory for the OPFmeta members: name and content. + Content attribute will be copied from EXTH record. + It will find first array index that is not already used + + @param[in] m MOBIData structure + @param[in] exth MOBIExthHeader structure containing EXTH records + @param[in,out] meta Array of OPFmeta structures to be filled with data + @param[in] name Value of the name attribute + */ +static void mobi_opf_copy_meta(const MOBIData *m, const MOBIExthHeader *exth, OPFmeta **meta, const char *name) { + MOBIExthMeta exth_tag = mobi_get_exthtagmeta_by_tag(exth->tag); + char *content = NULL; + if (exth_tag.tag == EXTH_COVEROFFSET) { + content = malloc(13 + 1); + if (content) { + const uint32_t val32 = mobi_decode_exthvalue(exth->data, exth->size); + snprintf(content, 14, "resource%05d", val32); + } + } else if (exth_tag.type == EXTH_NUMERIC) { + content = malloc(10 + 1); + if (content) { + const uint32_t val32 = mobi_decode_exthvalue(exth->data, exth->size); + snprintf(content, 11, "%d", val32); + } + } else if (exth_tag.type == EXTH_STRING) { + char *string = mobi_decode_exthstring(m, exth->data, exth->size); + content = string; + } + if (content) { + mobi_opf_set_meta(meta, name, content); + free(content); + } +} + +/** + @brief Set values for attributes of OPF manifest tag + + It will allocate memory for the OPFitem members: id, href and media-type. + It will find first array index that is not already used + + @param[in,out] meta Array of OPFmeta structures to be filled with data + @param[in] name Value of the name attribute + @param[in] content Value of the content attribute + */ +void mobi_opf_set_item(OPFmeta **meta, const char *name, const char *content) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + /* find first free slot */ + if(meta[i] != NULL) { i++; continue; } + meta[i] = malloc(sizeof(OPFmeta)); + if (meta[i] == NULL) { + return; + } + meta[i]->name = strdup(name); + meta[i]->content = strdup(content); + if (meta[i]->name == NULL || meta[i]->content == NULL) { + free(meta[i]); + meta[i] = NULL; + } + return; + } + /* not enough tags */ + debug_print("OPF_META_MAX_TAGS = %i reached\n", OPF_META_MAX_TAGS); +} + +/** + @brief Copy text data from EXTH record to "member_name" member of a structure with given type + + Data will copied from curr->data. + It will allocate memory for the array of structures if not already allocated. + It will find first array index that is not already used + + @param[in] mobidata Mobidata structure + @param[in] struct_type Structure type defined with typedef + @param[in] struct_element Member member_name of this structure will be set to EXTH data + @param[in] member_name Structure member name that will be modified + */ +#define mobi_opf_copy_tagtype(mobidata, struct_type, struct_element, member_name) { \ + if (struct_element == NULL) { \ + struct_element = calloc(OPF_META_MAX_TAGS, sizeof(*struct_element)); \ + if(struct_element == NULL) { \ + debug_print("%s\n", "Memory allocation failed"); \ + return MOBI_MALLOC_FAILED; \ + } \ + } \ + struct_type **element = struct_element; \ + size_t i = 0; \ + while (i < OPF_META_MAX_TAGS) { \ + /* find first free slot */ \ + if(element[i] != NULL) { \ + if(element[i]->member_name != NULL) { i++; continue; } \ + } else { \ + element[i] = calloc(1, sizeof(*element[i])); \ + if(element[i] == NULL) { \ + debug_print("%s\n", "Memory allocation failed"); \ + return MOBI_MALLOC_FAILED; \ + } \ + } \ + MOBIExthMeta exth_tag = mobi_get_exthtagmeta_by_tag(curr->tag); \ + char *value = NULL; \ + MOBI_RET error_ret = MOBI_DATA_CORRUPT; \ + if (exth_tag.type == EXTH_NUMERIC) { \ + value = malloc(10 + 1); \ + if (value) { \ + const uint32_t val32 = mobi_decode_exthvalue(curr->data, curr->size); \ + snprintf(value, 10 + 1, "%d", val32); \ + } else { \ + error_ret = MOBI_MALLOC_FAILED; \ + } \ + } else if (exth_tag.type == EXTH_STRING) { \ + value = mobi_decode_exthstring(mobidata, curr->data, curr->size); \ + } \ + if(value == NULL) { \ + free(element[i]); \ + element[i] = NULL; \ + debug_print("%s\n", "Decoding failed"); \ + return error_ret; \ + } \ + element[i]->member_name = value; \ + break; \ + } \ + if (i == OPF_META_MAX_TAGS) { \ + /* not enough tags */ \ + debug_print("OPF_META_MAX_TAGS = %i reached\n", OPF_META_MAX_TAGS); \ + } \ +} + +/** + @brief Set "member_name" member of a structure with given type to string value + + It will allocate memory for the array of structures if not already allocated. + It will find first array index that is not already used + + @param[in] struct_type Structure type defined with typedef + @param[in] struct_element Member member_name of this structure will be set to EXTH data + @param[in] member_name Structure member name that will be modified + @param[in] string String value that will be assigned to the structure memeber + */ +#define mobi_opf_set_tagtype(struct_type, struct_element, member_name, string) { \ + if (struct_element == NULL) { \ + struct_element = calloc(OPF_META_MAX_TAGS, sizeof(*struct_element)); \ + if(struct_element == NULL) { \ + debug_print("%s\n", "Memory allocation failed"); \ + return MOBI_MALLOC_FAILED; \ + } \ + } \ + struct_type **element = struct_element; \ + size_t i = 0; \ + while (i < OPF_META_MAX_TAGS) { \ + /* find first free slot */ \ + if(element[i] != NULL) { \ + if(element[i]->member_name != NULL) { i++; continue; } \ + } else { \ + element[i] = calloc(1, sizeof(*element[i])); \ + if(element[i] == NULL) { \ + debug_print("%s\n", "Memory allocation failed"); \ + return MOBI_MALLOC_FAILED; \ + } \ + } \ + element[i]->member_name = strdup(string); \ + if(element[i]->member_name == NULL) { \ + free(element[i]); \ + element[i] = NULL; \ + debug_print("%s\n", "Memory allocation failed"); \ + return MOBI_MALLOC_FAILED; \ + } \ + break; \ + } \ + if (i == OPF_META_MAX_TAGS) { \ + /* not enough tags */ \ + debug_print("OPF_META_MAX_TAGS = %i reached\n", OPF_META_MAX_TAGS); \ + } \ +} + +/** + @brief Copy text data from EXTH record to OPFmetadata tags structure + + @param[in,out] metadata Structure OPFmetadata will be filled with parsed data + @param[in] m MOBIData structure with loaded data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_opf_from_exth(OPFmetadata *metadata, const MOBIData *m) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (m->eh == NULL) { + return MOBI_INIT_FAILED; + } + MOBIExthHeader *curr = m->eh; + /* iterate through EXTH records */ + while (curr != NULL) { + switch (curr->tag) { + /* */ + case EXTH_DESCRIPTION: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->description); + break; + case EXTH_LANGUAGE: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->language); + break; + case EXTH_PUBLISHER: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->publisher); + break; + case EXTH_RIGHTS: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->rights); + break; + case EXTH_SOURCE: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->source); + break; + case EXTH_TITLE: + case EXTH_UPDATEDTITLE: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->title); + break; + case EXTH_TYPE: + mobi_opf_fill_tag(m, curr, &metadata->dc_meta->type); + break; + case EXTH_AUTHOR: + mobi_opf_copy_tagtype(m, OPFcreator, metadata->dc_meta->creator, value); + break; + case EXTH_CONTRIBUTOR: + mobi_opf_copy_tagtype(m, OPFcreator, metadata->dc_meta->contributor, value); + break; + case EXTH_SUBJECT: + mobi_opf_copy_tagtype(m, OPFsubject, metadata->dc_meta->subject, value); + break; + case EXTH_SUBJECTCODE: + mobi_opf_copy_tagtype(m, OPFsubject, metadata->dc_meta->subject, basic_code); + break; + case EXTH_ISBN: + mobi_opf_copy_tagtype(m, OPFidentifier, metadata->dc_meta->identifier, value); + mobi_opf_set_tagtype(OPFidentifier, metadata->dc_meta->identifier, scheme, "ISBN"); + break; + case EXTH_PUBLISHINGDATE: + mobi_opf_copy_tagtype(m, OPFdate, metadata->dc_meta->date, value); + mobi_opf_set_tagtype(OPFdate, metadata->dc_meta->date, event, "publication"); + break; + /* */ + case EXTH_ADULT: + mobi_opf_fill_tag(m, curr, &metadata->x_meta->adult); + break; + case EXTH_DICTNAME: + mobi_opf_fill_tag(m, curr, &metadata->x_meta->dict_short_name); + break; + case EXTH_DICTLANGIN: + mobi_opf_fill_tag(m, curr, &metadata->x_meta->dictionary_in_lang); + break; + case EXTH_DICTLANGOUT: + mobi_opf_fill_tag(m, curr, &metadata->x_meta->dictionary_out_lang); + break; + case EXTH_IMPRINT: + mobi_opf_fill_tag(m, curr, &metadata->x_meta->imprint); + break; + case EXTH_REVIEW: + mobi_opf_fill_tag(m, curr, &metadata->x_meta->review); + break; + case EXTH_PRICE: + mobi_opf_copy_tagtype(m, OPFsrp, metadata->x_meta->srp, value); + break; + case EXTH_CURRENCY: + mobi_opf_copy_tagtype(m, OPFsrp, metadata->x_meta->srp, currency); + break; + /* */ + case EXTH_FIXEDLAYOUT: + mobi_opf_copy_meta(m, curr, metadata->meta, "fixed-layout"); + break; + case EXTH_BOOKTYPE: + mobi_opf_copy_meta(m, curr, metadata->meta, "book-type"); + break; + case EXTH_ORIENTATIONLOCK: + mobi_opf_copy_meta(m, curr, metadata->meta, "orientation-lock"); + break; + case EXTH_ORIGRESOLUTION: + mobi_opf_copy_meta(m, curr, metadata->meta, "original-resolution"); + break; + case EXTH_ZEROGUTTER: + mobi_opf_copy_meta(m, curr, metadata->meta, "zero-gutter"); + break; + case EXTH_ZEROMARGIN: + mobi_opf_copy_meta(m, curr, metadata->meta, "zero-margin"); + break; + case EXTH_REGIONMAGNI: + mobi_opf_copy_meta(m, curr, metadata->meta, "region-mag"); + break; + case EXTH_ALIGNMENT: + mobi_opf_copy_meta(m, curr, metadata->meta, "primary-writing-mode"); + break; + case EXTH_OVERRIDEFONTS: + mobi_opf_copy_meta(m, curr, metadata->meta, "override-kindle-fonts"); + break; + case EXTH_COVEROFFSET: + mobi_opf_copy_meta(m, curr, metadata->meta, "cover"); + break; + default: + break; + } + curr = curr->next; + } + return MOBI_SUCCESS; +} + +/** + @brief Recreate OPF structure + + @param[in,out] opf Structure OPF->OPFmetadata will be filled with parsed data + @param[in] m MOBIData structure containing document metadata + @param[in] rawml MOBIRawml structure containing parsed records + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_build_opf_metadata(OPF *opf, const MOBIData *m, const MOBIRawml *rawml) { + if (m == NULL) { + debug_print("%s\n", "Initialization failed"); + return MOBI_INIT_FAILED; + } + opf->metadata = calloc(1, sizeof(OPFmetadata)); + if (opf->metadata == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + /* initialize metadata sub-elements */ + opf->metadata->meta = calloc(OPF_META_MAX_TAGS, sizeof(OPFmeta*)); + if (opf->metadata->meta == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + opf->metadata->dc_meta = calloc(1, sizeof(OPFdcmeta)); + if (opf->metadata->dc_meta == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + opf->metadata->x_meta = calloc(1, sizeof(OPFxmeta)); + if (opf->metadata->x_meta == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (m->eh) { + MOBI_RET ret = mobi_get_opf_from_exth(opf->metadata, m); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + /* check for required elements */ + if (opf->metadata->dc_meta->identifier == NULL) { + /* default id will be "0" */ + char uid_string[11] = "0"; + if (m->mh && m->mh->uid) { + snprintf(uid_string, 11, "%u", *m->mh->uid); + } + mobi_opf_set_tagtype(OPFidentifier, opf->metadata->dc_meta->identifier, value, uid_string); + mobi_opf_set_tagtype(OPFidentifier, opf->metadata->dc_meta->identifier, id, "uid"); + } else { + opf->metadata->dc_meta->identifier[0]->id = strdup("uid"); + } + if (opf->metadata->dc_meta->title == NULL) { + opf->metadata->dc_meta->title = calloc(OPF_META_MAX_TAGS, sizeof(char*)); + if (opf->metadata->dc_meta->title == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char *title = mobi_meta_get_title(m); + if (title == NULL) { + title = strdup("Unknown"); + } + opf->metadata->dc_meta->title[0] = title; + } + if (opf->metadata->dc_meta->language == NULL) { + opf->metadata->dc_meta->language = calloc(OPF_META_MAX_TAGS, sizeof(char*)); + if (opf->metadata->dc_meta->language == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + const char *lang_string = NULL; + if (m->mh && m->mh->locale) { + uint32_t lang_code = *m->mh->locale; + lang_string = mobi_get_locale_string(lang_code); + } + if (lang_string) { + opf->metadata->dc_meta->language[0] = strdup(lang_string); + } else { + opf->metadata->dc_meta->language[0] = strdup("en"); + } + } + /* write optional elements */ + if (mobi_is_dictionary(m)) { + if (opf->metadata->x_meta->dictionary_in_lang == NULL) { + if (m->mh && m->mh->dict_input_lang) { + uint32_t dict_lang_in = *m->mh->dict_input_lang; + const char *lang = mobi_get_locale_string(dict_lang_in); + if (lang) { + opf->metadata->x_meta->dictionary_in_lang = calloc(OPF_META_MAX_TAGS, sizeof(char*)); + if (opf->metadata->x_meta->dictionary_in_lang == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + opf->metadata->x_meta->dictionary_in_lang[0] = strdup(lang); + } + } + } + if (opf->metadata->x_meta->dictionary_out_lang == NULL) { + if (m->mh && m->mh->dict_output_lang) { + uint32_t dict_lang_out = *m->mh->dict_output_lang; + const char *lang = mobi_get_locale_string(dict_lang_out); + if (lang) { + opf->metadata->x_meta->dictionary_out_lang = calloc(OPF_META_MAX_TAGS, sizeof(char*)); + if (opf->metadata->x_meta->dictionary_out_lang == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + opf->metadata->x_meta->dictionary_out_lang[0] = strdup(lang); + } + } + } + if (rawml->orth && rawml->orth->orth_index_name) { + opf->metadata->x_meta->default_lookup_index = calloc(OPF_META_MAX_TAGS, sizeof(char*)); + if (opf->metadata->x_meta->default_lookup_index == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + opf->metadata->x_meta->default_lookup_index[0] = strdup(rawml->orth->orth_index_name); + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of xml elements of given name to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] name XML element name + @param[in] content Array of XML element contents + @param[in] ns XML namespace string or NULL if empty + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_element_ns(xmlTextWriterPtr writer, const char *name, const char **content, const char *ns) { + if (content) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (content[i] == NULL) { + break; + } + xmlChar *namespace = NULL; + if (ns) { + namespace = BAD_CAST ns; + } + int xml_ret = xmlTextWriterWriteElementNS(writer, namespace, BAD_CAST name, NULL, BAD_CAST content[i]); + if (xml_ret < 0) { + debug_print("XML error: %i (name: %s, content: %s)\n", xml_ret, name, content[i]); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of Dublin Core elements of given name to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] name XML element name + @param[in] content Array of XML element contents + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_dcmeta(xmlTextWriterPtr writer, const char *name, const char **content) { + return mobi_xml_write_element_ns(writer, name, content, "dc"); +} + +/** + @brief Write array of custom MOBI elements of given name to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] name XML element name + @param[in] content Array of XML element contents + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_xmeta(xmlTextWriterPtr writer, const char *name, const char **content) { + return mobi_xml_write_element_ns(writer, name, content, NULL); +} + +/** + @brief Write array of elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElement() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] meta Array of OPFmeta structures + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_opfmeta(xmlTextWriterPtr writer, const OPFmeta **meta) { + if (meta) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (meta[i] == NULL) { + break; + } + MOBI_RET ret = mobi_xml_write_meta(writer, meta[i]->name, meta[i]->content); + if (ret != MOBI_SUCCESS) { + return ret; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElement() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] reference Array of OPFreference structures + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_reference(xmlTextWriterPtr writer, const OPFreference **reference) { + if (reference) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (reference[i] == NULL) { + break; + } + int xml_ret; + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "reference"); + if (xml_ret < 0) { + debug_print("XML error: %i (reference type: %s)\n", xml_ret, reference[i]->type); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST reference[i]->type); + if (xml_ret < 0) { + debug_print("XML error: %i (reference type: %s)\n", xml_ret, reference[i]->type); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "title", BAD_CAST reference[i]->title); + if (xml_ret < 0) { + debug_print("XML error: %i (reference type: %s)\n", xml_ret, reference[i]->type); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "href", BAD_CAST reference[i]->href); + if (xml_ret < 0) { + debug_print("XML error: %i (reference type: %s)\n", xml_ret, reference[i]->type); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (reference type: %s)\n", xml_ret, reference[i]->type); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write single element to XML buffer + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] id Attribute "id" + @param[in] href Attribute "href" + @param[in] media_type Attribute "media-type" + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_item(xmlTextWriterPtr writer, const char *id, const char *href, const char *media_type) { + int xml_ret; + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "item"); + if (xml_ret < 0) { + debug_print("XML error: %i (item id: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST id); + if (xml_ret < 0) { + debug_print("XML error: %i (item id: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "href", BAD_CAST href); + if (xml_ret < 0) { + debug_print("XML error: %i (item id: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "media-type", BAD_CAST media_type); + if (xml_ret < 0) { + debug_print("XML error: %i (item id: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (item id: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + return MOBI_SUCCESS; +} + +/** + @brief Write opf part to XML buffer + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] rawml MOBIRawml structure containing parts metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_spine(xmlTextWriterPtr writer, const MOBIRawml *rawml) { + if (!rawml || !rawml->resources || !rawml->markup || !writer) { + return MOBI_INIT_FAILED; + } + /* get toc id */ + char ncxid[13 + 1]; + MOBIPart *curr = rawml->resources; + while (curr != NULL && curr->type != T_NCX) { + curr = curr->next; + } + if (curr) { + snprintf(ncxid, sizeof(ncxid), "resource%05zu", curr->uid); + } else { + return MOBI_DATA_CORRUPT; + } + int xml_ret; + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "spine"); + if (xml_ret < 0) { + debug_print("XML error: %i (spine)\n", xml_ret); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "toc", BAD_CAST ncxid); + if (xml_ret < 0) { + debug_print("XML error: %i (spine toc: %s)\n", xml_ret, ncxid); + return MOBI_XML_ERR; + } + char id[9 + 1]; + curr = rawml->markup; + while (curr != NULL) { + snprintf(id, sizeof(id), "part%05zu", curr->uid); + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "itemref"); + if (xml_ret < 0) { + debug_print("XML error: %i (itemref)\n", xml_ret); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "idref", BAD_CAST id); + if (xml_ret < 0) { + debug_print("XML error: %i (idref: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (idref: %s)\n", xml_ret, id); + return MOBI_XML_ERR; + } + curr = curr->next; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (spine)\n", xml_ret); + return MOBI_XML_ERR; + } + return MOBI_SUCCESS; +} + +/** + @brief Write all manifest elements to XML buffer + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] rawml MOBIRawml structure containing parts metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_manifest(xmlTextWriterPtr writer, const MOBIRawml *rawml) { + char href[256]; + char id[256]; + if (rawml->flow != NULL) { + MOBIPart *curr = rawml->flow; + /* skip first raw html part */ + curr = curr->next; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(href, sizeof(href), "flow%05zu.%s", curr->uid, file_meta.extension); + snprintf(id, sizeof(id), "flow%05zu", curr->uid); + MOBI_RET ret = mobi_xml_write_item(writer, id, href, file_meta.mime_type); + if (ret != MOBI_SUCCESS) { + return ret; + } + curr = curr->next; + } + } + if (rawml->markup != NULL) { + MOBIPart *curr = rawml->markup; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(href, sizeof(href), "part%05zu.%s", curr->uid, file_meta.extension); + snprintf(id, sizeof(id), "part%05zu", curr->uid); + MOBI_RET ret = mobi_xml_write_item(writer, id, href, file_meta.mime_type); + if (ret != MOBI_SUCCESS) { + return ret; + } + curr = curr->next; + } + } + if (rawml->resources != NULL) { + MOBIPart *curr = rawml->resources; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(href, sizeof(href), "resource%05zu.%s", curr->uid, file_meta.extension); + snprintf(id, sizeof(id), "resource%05zu", curr->uid); + MOBI_RET ret = mobi_xml_write_item(writer, id, href, file_meta.mime_type); + if (ret != MOBI_SUCCESS) { + return ret; + } + curr = curr->next; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of Dublin Core identifier elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] identifier OPFidentifier structure representing identifier element + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_dcmeta_identifier(xmlTextWriterPtr writer, const OPFidentifier **identifier) { + if (identifier) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (identifier[i] == NULL || identifier[i]->value == NULL) { + break; + } + int xml_ret; + xml_ret = xmlTextWriterStartElementNS(writer, BAD_CAST "dc", BAD_CAST "identifier", NULL); + if (xml_ret < 0) { + debug_print("XML error: %i (identifier value: %s)\n", xml_ret, identifier[i]->value); + return MOBI_XML_ERR; + } + if (identifier[i]->id) { + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST identifier[i]->id); + if (xml_ret < 0) { + debug_print("XML error: %i (identifier id: %s)\n", xml_ret, identifier[i]->id); + return MOBI_XML_ERR; + } + } + if (identifier[i]->scheme) { + xml_ret = xmlTextWriterWriteAttributeNS(writer, BAD_CAST "opf", BAD_CAST "scheme", NULL, BAD_CAST identifier[i]->scheme); + if (xml_ret < 0) { + debug_print("XML error: %i (identifier value: %s)\n", xml_ret, identifier[i]->value); + return MOBI_XML_ERR; + } + } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST identifier[i]->value); + if (xml_ret < 0) { + debug_print("XML error: %i (identifier value: %s)\n", xml_ret, identifier[i]->value); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (identifier value: %s)\n", xml_ret, identifier[i]->value); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of Dublin Core creator/contributor elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] creator OPFcreator structure representing creator/contributor element + @param[in] name OPF creator value + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_dcmeta_creator(xmlTextWriterPtr writer, const OPFcreator **creator, const char *name) { + if (creator) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (creator[i] == NULL || creator[i]->value == NULL) { + break; + } + int xml_ret; + xml_ret = xmlTextWriterStartElementNS(writer, BAD_CAST "dc", BAD_CAST name, NULL); + if (xml_ret < 0) { + debug_print("XML error: %i (creator value: %s)\n", xml_ret, creator[i]->value); + return MOBI_XML_ERR; + } + if (creator[i]->role) { + xml_ret = xmlTextWriterWriteAttributeNS(writer, BAD_CAST "opf", BAD_CAST "role", NULL, BAD_CAST creator[i]->role); + if (xml_ret < 0) { + debug_print("XML error: %i (creator role: %s)\n", xml_ret, creator[i]->role); + return MOBI_XML_ERR; + } + } + if (creator[i]->file_as) { + xml_ret = xmlTextWriterWriteAttributeNS(writer, BAD_CAST "opf", BAD_CAST "file-as", NULL, BAD_CAST creator[i]->file_as); + if (xml_ret < 0) { + debug_print("XML error: %i (creator file-as: %s)\n", xml_ret, creator[i]->file_as); + return MOBI_XML_ERR; + } + } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST creator[i]->value); + if (xml_ret < 0) { + debug_print("XML error: %i (creator value: %s)\n", xml_ret, creator[i]->value); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (creator value: %s)\n", xml_ret, creator[i]->value); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of Dublin Core subject elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] subject OPFsubject structure representing subject element + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_dcmeta_subject(xmlTextWriterPtr writer, const OPFsubject **subject) { + if (subject) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (subject[i] == NULL || subject[i]->value == NULL) { + break; + } + int xml_ret; + xml_ret = xmlTextWriterStartElementNS(writer, BAD_CAST "dc", BAD_CAST "subject", NULL); + if (xml_ret < 0) { + debug_print("XML error: %i (subject value: %s)\n", xml_ret, subject[i]->value); + return MOBI_XML_ERR; + } + if (subject[i]->basic_code) { + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "BASICCode", BAD_CAST subject[i]->basic_code); + if (xml_ret < 0) { + debug_print("XML error: %i (subject BASICCode: %s)\n", xml_ret, subject[i]->basic_code); + return MOBI_XML_ERR; + } + } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST subject[i]->value); + if (xml_ret < 0) { + debug_print("XML error: %i (subject value: %s)\n", xml_ret, subject[i]->value); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (subject value: %s)\n", xml_ret, subject[i]->value); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of Dublin Core date elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] date OPFdate structure representing date element + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_dcmeta_date(xmlTextWriterPtr writer, const OPFdate **date) { + if (date) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (date[i] == NULL || date[i]->value == NULL) { + break; + } + int xml_ret; + xml_ret = xmlTextWriterStartElementNS(writer, BAD_CAST "dc", BAD_CAST "date", NULL); + if (xml_ret < 0) { + debug_print("XML error: %i (date value: %s)\n", xml_ret, date[i]->value); + return MOBI_XML_ERR; + } + if (date[i]->event) { + xml_ret = xmlTextWriterWriteAttributeNS(writer, BAD_CAST "opf", BAD_CAST "event", NULL, BAD_CAST date[i]->event); + if (xml_ret < 0) { + debug_print("XML error: %i (date event: %s)\n", xml_ret, date[i]->event); + return MOBI_XML_ERR; + } + } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST date[i]->value); + if (xml_ret < 0) { + debug_print("XML error: %i (date value: %s)\n", xml_ret, date[i]->value); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (date value: %s)\n", xml_ret, date[i]->value); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Write array of custom srp elements to XML buffer + + Wrapper for libxml2 xmlTextWriterWriteElementNS() function. + Writes xml element for each not-null entry in the input array. + + @param[in,out] writer xmlTextWriterPtr to write to + @param[in] srp OPFsrp structure representing srp element + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_xml_write_xmeta_srp(xmlTextWriterPtr writer, const OPFsrp **srp) { + if (srp) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (srp[i] == NULL || srp[i]->value == NULL) { + break; + } + int xml_ret; + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "srp"); + if (xml_ret < 0) { + debug_print("XML error: %i (srp value: %s)\n", xml_ret, srp[i]->value); + return MOBI_XML_ERR; + } + if (srp[i]->currency) { + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "currency", BAD_CAST srp[i]->currency); + if (xml_ret < 0) { + debug_print("XML error: %i (srp currency: %s)\n", xml_ret, srp[i]->currency); + return MOBI_XML_ERR; + } + } + xml_ret = xmlTextWriterWriteString(writer, BAD_CAST srp[i]->value); + if (xml_ret < 0) { + debug_print("XML error: %i (srp value: %s)\n", xml_ret, srp[i]->value); + return MOBI_XML_ERR; + } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { + debug_print("XML error: %i (srp value: %s)\n", xml_ret, srp[i]->value); + return MOBI_XML_ERR; + } + i++; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Free array of OPF sturcture members + + @param[in] array Array + */ +void mobi_free_opf_array(char **array) { + if (array) { + size_t i = 0; + while (i < OPF_META_MAX_TAGS) { + if (array[i] == NULL) { + break; + } + free(array[i]); + i++; + } + free(array); + } +} + +/** + @brief Macro to free generic OPF structure with two members + + @param[in] struct_array Structure name + @param[in] struct_member1 Structure member 1 + @param[in] struct_member2 Structure member 2 + */ +#define mobi_free_opf_struct_2el(struct_array, struct_member1, struct_member2) { \ + if (struct_array) { \ + size_t i = 0; \ + while (i < OPF_META_MAX_TAGS) { \ + if (struct_array[i] == NULL) { \ + break; \ + } \ + free(struct_array[i]->struct_member1); \ + free(struct_array[i]->struct_member2); \ + free(struct_array[i]); \ + i++; \ + } \ + free(struct_array); \ + } \ +} + +/** + @brief Macro to free generic OPF structure with three members + + @param[in] struct_array Structure name + @param[in] struct_member1 Structure member 1 + @param[in] struct_member2 Structure member 2 + @param[in] struct_member3 Structure member 3 + */ +#define mobi_free_opf_struct_3el(struct_array, struct_member1, struct_member2, struct_member3) { \ + if (struct_array) { \ + size_t i = 0; \ + while (i < OPF_META_MAX_TAGS) { \ + if (struct_array[i] == NULL) { \ + break; \ + } \ + free(struct_array[i]->struct_member1); \ + free(struct_array[i]->struct_member2); \ + free(struct_array[i]->struct_member3); \ + free(struct_array[i]); \ + i++; \ + } \ + free(struct_array); \ + } \ +} + +/** + @brief Free OPF metadata structure and data + + @param[in] metadata OPF opf->metadata structure + */ +void mobi_free_opf_metadata(OPFmetadata *metadata) { + if (metadata) { + /* */ + mobi_free_opf_struct_2el(metadata->meta, name, content); + /* */ + mobi_free_opf_struct_3el(metadata->dc_meta->contributor, value, file_as, role); + mobi_free_opf_struct_3el(metadata->dc_meta->creator, value, file_as, role); + mobi_free_opf_struct_3el(metadata->dc_meta->identifier, value, id, scheme); + mobi_free_opf_struct_2el(metadata->dc_meta->subject, value, basic_code); + mobi_free_opf_struct_2el(metadata->dc_meta->date, value, event); + mobi_free_opf_array(metadata->dc_meta->description); + mobi_free_opf_array(metadata->dc_meta->language); + mobi_free_opf_array(metadata->dc_meta->publisher); + mobi_free_opf_array(metadata->dc_meta->rights); + mobi_free_opf_array(metadata->dc_meta->source); + mobi_free_opf_array(metadata->dc_meta->title); + mobi_free_opf_array(metadata->dc_meta->type); + free(metadata->dc_meta); + /* */ + mobi_free_opf_struct_2el(metadata->x_meta->srp, value, currency); + mobi_free_opf_array(metadata->x_meta->adult); + mobi_free_opf_array(metadata->x_meta->default_lookup_index); + mobi_free_opf_array(metadata->x_meta->dict_short_name); + mobi_free_opf_array(metadata->x_meta->dictionary_in_lang); + mobi_free_opf_array(metadata->x_meta->dictionary_out_lang); + mobi_free_opf_array(metadata->x_meta->embedded_cover); + mobi_free_opf_array(metadata->x_meta->imprint); + mobi_free_opf_array(metadata->x_meta->review); + free(metadata->x_meta); + free(metadata); + } +} + +/** + @brief Free OPFmanifest structure and data + + @param[in] manifest OPF opf->manifest structure + */ +void mobi_free_opf_manifest(OPFmanifest *manifest) { + if (manifest) { + mobi_free_opf_struct_3el(manifest->item, id, href, media_type); + free(manifest); + } +} + +/** + @brief Free OPFspine structure and data + + @param[in] spine OPF opf->spine structure + */ +void mobi_free_opf_spine(OPFspine *spine) { + if (spine) { + mobi_free_opf_array(spine->itemref); + free(spine->toc); + free(spine); + } +} + +/** + @brief Free OPFguide structure and data + + @param[in] guide OPF opf->guide structure + */ +void mobi_free_opf_guide(OPFguide *guide) { + if (guide) { + mobi_free_opf_struct_3el(guide->reference, type, title, href); + free(guide); + } +} + +/** + @brief Free OPF structure and data + + @param[in] opf OPF structure + */ +void mobi_free_opf(OPF *opf) { + mobi_free_opf_metadata(opf->metadata); + mobi_free_opf_manifest(opf->manifest); + mobi_free_opf_spine(opf->spine); + mobi_free_opf_guide(opf->guide); +} + +/** + @brief Recreate OPF structure + + This function will fill OPF structure with parsed index data and convert it to xml file. The file will be stored in MOBIRawml structure. + + @param[in,out] rawml OPF xml file will be appended to rawml->markup linked list + @param[in] m MOBIData structure containing document metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_build_opf(MOBIRawml *rawml, const MOBIData *m) { + debug_print("Reconstructing opf%s", "\n"); + /* initialize libXML2 */ + LIBXML_TEST_VERSION + /* initialize OPF structure */ + OPF opf = { + .metadata = NULL, + .manifest = NULL, + .guide = NULL, + .spine = NULL + }; + MOBI_RET ret = mobi_build_opf_metadata(&opf, m, rawml); + if (ret != MOBI_SUCCESS) { + mobi_free_opf(&opf); + return ret; + } + mobi_build_ncx(rawml, &opf); + if (rawml->guide) { + ret = mobi_build_opf_guide(&opf, rawml); + if (ret != MOBI_SUCCESS) { + mobi_free_opf(&opf); + return ret; + } + } + + /* build OPF xml document */ + int xml_ret; + const xmlChar * OPFNamespace = BAD_CAST "http://www.idpf.org/2007/opf"; + const xmlChar * DCNamespace = BAD_CAST "http://purl.org/dc/elements/1.1/"; + xmlBufferPtr buf = xmlBufferCreate(); + if (buf == NULL) { + mobi_free_opf(&opf); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + xmlTextWriterPtr writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + xmlBufferFree(buf); + mobi_free_opf(&opf); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + xmlTextWriterSetIndent(writer, 1); + xml_ret = xmlTextWriterStartDocument(writer, NULL, NULL, NULL); + if (xml_ret < 0) { goto cleanup; } + /* */ + xml_ret = xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "package", OPFNamespace); + if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "2.0"); + if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "unique-identifier", BAD_CAST "uid"); + if (xml_ret < 0) { goto cleanup; } + /* */ + xml_ret = xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "metadata", NULL); + if (xml_ret < 0) { goto cleanup; } + /* */ + //xml_ret = xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "dc-metadata", NULL); + //if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterWriteAttributeNS(writer, BAD_CAST "xmlns", BAD_CAST "opf", NULL, OPFNamespace); + if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterWriteAttributeNS(writer, BAD_CAST "xmlns", BAD_CAST "dc", NULL, DCNamespace); + if (xml_ret < 0) { goto cleanup; } + /* Dublin Core elements */ + OPFdcmeta *dc_meta = opf.metadata->dc_meta; + ret = mobi_xml_write_dcmeta(writer, "title", (const char **) dc_meta->title); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta(writer, "description", (const char **) dc_meta->description); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta(writer, "language", (const char **) dc_meta->language); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta(writer, "publisher", (const char **) dc_meta->publisher); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta(writer, "rights", (const char **) dc_meta->rights); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta(writer, "source", (const char **) dc_meta->source); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta(writer, "type", (const char **) dc_meta->type); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta_identifier(writer, (const OPFidentifier **) dc_meta->identifier); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta_creator(writer, (const OPFcreator **) dc_meta->creator, "creator"); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta_creator(writer, (const OPFcreator **) dc_meta->contributor, "contributor"); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta_subject(writer, (const OPFsubject **) dc_meta->subject); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_dcmeta_date(writer, (const OPFdate **) dc_meta->date); + if (ret != MOBI_SUCCESS) { goto cleanup; } + //xml_ret = xmlTextWriterEndElement(writer); + //if (xml_ret < 0) { goto cleanup; } + /* */ + //xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "x-metadata"); + //if (xml_ret < 0) { goto cleanup; } + OPFxmeta *x_meta = opf.metadata->x_meta; + /* custom elements */ + ret = mobi_xml_write_xmeta_srp(writer, (const OPFsrp **) x_meta->srp); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "adult", (const char **) x_meta->adult); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "DefaultLookupIndex", (const char **) x_meta->default_lookup_index); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "DictionaryVeryShortName", (const char **) x_meta->dict_short_name); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "DictionaryInLanguage", (const char **) x_meta->dictionary_in_lang); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "DictionaryOutLanguage", (const char **) x_meta->dictionary_out_lang); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "EmbeddedCover", (const char **) x_meta->embedded_cover); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "imprint", (const char **) x_meta->imprint); + if (ret != MOBI_SUCCESS) { goto cleanup; } + ret = mobi_xml_write_xmeta(writer, "review", (const char **) x_meta->review); + if (ret != MOBI_SUCCESS) { goto cleanup; } + /* */ + ret = mobi_xml_write_opfmeta(writer, (const OPFmeta **) opf.metadata->meta); + if (ret != MOBI_SUCCESS) { goto cleanup; } + //xml_ret = xmlTextWriterEndElement(writer); + //if (xml_ret < 0) { goto cleanup; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { goto cleanup; } + /* */ + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "manifest"); + if (xml_ret < 0) { goto cleanup; } + ret = mobi_xml_write_manifest(writer, rawml); + if (ret != MOBI_SUCCESS) { goto cleanup; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { goto cleanup; } + /* */ + ret = mobi_xml_write_spine(writer, rawml); + if (ret != MOBI_SUCCESS) { goto cleanup; } + /* */ + if (opf.guide) { + xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "guide"); + if (xml_ret < 0) { goto cleanup; } + ret = mobi_xml_write_reference(writer, (const OPFreference **) opf.guide->reference); + if (ret != MOBI_SUCCESS) { goto cleanup; } + xml_ret = xmlTextWriterEndElement(writer); + if (xml_ret < 0) { goto cleanup; } + } + xml_ret = xmlTextWriterEndDocument(writer); + if (xml_ret < 0) { goto cleanup; } + + xmlFreeTextWriter(writer); + const char *opf_xml = (const char *) buf->content; + mobi_opf_add_to_rawml(opf_xml, rawml); + xmlBufferFree(buf); + mobi_free_opf(&opf); + /* cleanup function for the XML library */ + xmlCleanupParser(); + return MOBI_SUCCESS; + +cleanup: + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + mobi_free_opf(&opf); + xmlCleanupParser(); + debug_print("%s\n", "XML writing failed"); + return MOBI_XML_ERR; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/opf.h b/Charcoal/Charcoal/libmobi-public/src/opf.h new file mode 100644 index 0000000..52b6c2d --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/opf.h @@ -0,0 +1,164 @@ +/** @file opf.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_opf_h +#define libmobi_opf_h + +#include "config.h" +#include "mobi.h" + +/** @brief Maximum number of opf meta tags */ +#define OPF_META_MAX_TAGS 256 + +/** + @defgroup mobi_opf OPF handling structures + @{ + */ + +/** @brief OPF element structure + + At least one identifier must have an id specified, + so it can be referenced from the package unique-identifier attribute. + */ +typedef struct { + char *value; /**< element value */ + char *id; /**< id attribute */ + char *scheme; /**< opf:scheme (optional) */ +} OPFidentifier; + +/** @brief OPF element structure + + Also applies to element + */ +typedef struct { + char *value; /**< element value */ + char *file_as; /**< opf:file-as attribute (optional) */ + char *role; /**< opf:role attribute (optional) */ +} OPFcreator; + +/** @brief OPF element structure */ +typedef struct { + char *value; /**< element value */ + char *basic_code; /**< BASICCode attribute (optional, non-standard) */ +} OPFsubject; + +/** @brief OPF element structure + + Format: YYYY[-MM[-DD]] + */ +typedef struct { + char *value; /**< element value */ + char *event; /**< opf:event attribute (optional) */ +} OPFdate; + +/** @brief OPF element structure */ +typedef struct { + OPFcreator **contributor; /**< element (optional) */ + OPFcreator **creator; /**< element (optional) */ + OPFidentifier **identifier; /**< element (required) */ + OPFsubject **subject; /**< element (optional) */ + OPFdate **date; /**< element (optional) */ + char **description; /**< element (optional) */ + char **language; /**< element (required) */ + char **publisher; /**< element (optional) */ + char **rights; /**< element (optional) */ + char **source; /**< element (optional) */ + char **title; /**< element (required) */ + char **type; /**< element (optional) */ +} OPFdcmeta; + +/** @brief OPF element structure */ +typedef struct { + char *value; /**< element value */ + char *currency; /**< currency attribute */ +} OPFsrp; + +/** @brief OPF element structure */ +typedef struct { + OPFsrp **srp; /**< element */ + char **adult; /**< element */ + char **default_lookup_index; /**< element */ + char **dict_short_name; /**< element */ + char **dictionary_in_lang; /**< element */ + char **dictionary_out_lang; /**< element */ + char **embedded_cover; /**< element */ + char **imprint; /**< element */ + char **review; /**< element */ +} OPFxmeta; + +/** @brief OPF element structure */ +typedef struct { + char *name; /**< name attribute (required) */ + char *content; /**< content attribute (required) */ +} OPFmeta; + +/** @brief OPF element structure */ +typedef struct { + OPFmeta **meta; /**< element (optional) */ + OPFdcmeta *dc_meta; /**< element */ + OPFxmeta *x_meta; /**< element */ +} OPFmetadata; + +/** @brief OPF element structure */ +typedef struct { + char *id; /**< id attribute (required) */ + char *href; /**< href attribute (required) */ + char *media_type; /**< media-type attribute (required) */ +} OPFitem; + +/** @brief OPF element structure */ +typedef struct { + OPFitem **item; /**< element */ +} OPFmanifest; + +/** @brief OPF element structure */ +typedef struct { + char *toc; /**< toc attribute (required) */ + char **itemref; /**< element */ +} OPFspine; + +/** @brief OPF tag structure */ +typedef struct { + char *type; /**< type attribute (required) */ + char *title; /**< title attribute */ + char *href; /**< href attribute (required) */ +} OPFreference; + +/** @brief OPF element structure */ +typedef struct { + OPFreference **reference; /**< element tag */ +} OPFguide; + +/** @brief OPF element structure */ +typedef struct { + //char *uid; /**< */ + OPFmetadata *metadata; /**< (required) */ + OPFmanifest *manifest; /**< (required) */ + OPFspine *spine; /**< (required) */ + OPFguide *guide; /**< (optional) */ +} OPF; + +/** @brief NCX index entry structure */ +typedef struct { + size_t id; /**< Sequential id */ + char *text; /**< Entry text content */ + char *target; /**< Entry target reference */ + size_t level; /**< Entry level */ + size_t parent; /**< Entry parent */ + size_t first_child; /**< First child id */ + size_t last_child; /**< Last child id */ +} NCX; +/** @} */ + + +MOBI_RET mobi_build_opf(MOBIRawml *rawml, const MOBIData *m); +MOBI_RET mobi_build_ncx(MOBIRawml *rawml, const OPF *opf); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/parse_rawml.c b/Charcoal/Charcoal/libmobi-public/src/parse_rawml.c new file mode 100644 index 0000000..08afaf6 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/parse_rawml.c @@ -0,0 +1,2199 @@ +/** @file parse_rawml.c + * @brief Functions for parsing rawml markup + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#define _GNU_SOURCE 1 +#ifndef __USE_BSD +#define __USE_BSD /* for strdup on linux/glibc */ +#endif + +#include +#include +#include +#include "parse_rawml.h" +#include "util.h" +#include "opf.h" +#include "structure.h" +#include "index.h" +#include "debug.h" +#if defined(__BIONIC__) && !defined(SIZE_MAX) +#include /* for SIZE_MAX */ +#endif + +/** + @brief Convert kindle:pos:fid:x:off:y to offset in rawml raw text file + + @param[in] rawml MOBIRawml parsed records structure + @param[in] pos_fid X value of pos:fid:x + @param[in] pos_off Y value of off:y + @return Offset in rawml buffer on success, SIZE_MAX otherwise + */ +size_t mobi_get_rawlink_location(const MOBIRawml *rawml, const uint32_t pos_fid, const uint32_t pos_off) { + if (!rawml || !rawml->frag || !rawml->frag->entries ) { + debug_print("%s", "Initialization failed\n"); + return SIZE_MAX; + } + if (pos_fid >= rawml->frag->entries_count) { + debug_print("%s", "pos_fid not found\n"); + return SIZE_MAX; + } + const MOBIIndexEntry *entry = &rawml->frag->entries[pos_fid]; + const size_t insert_position = strtoul(entry->label, NULL, 10); + size_t file_offset = insert_position + pos_off; + return file_offset; +} + +/** + @brief Find first occurence of attribute to be replaced in KF7 html + + It searches for filepos and recindex attributes + + @param[in,out] result MOBIResult structure will be filled with found data + @param[in] data_start Beginning of the memory area to search in + @param[in] data_end End of the memory area to search in + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_search_links_kf7(MOBIResult *result, const unsigned char *data_start, const unsigned char *data_end) { + if (!result) { + debug_print("Result structure is null%s", "\n"); + return MOBI_PARAM_ERR; + } + result->start = result->end = NULL; + *(result->value) = '\0'; + if (!data_start || !data_end) { + debug_print("Data is null%s", "\n"); + return MOBI_PARAM_ERR; + } + const char *needle1 = "filepos="; + const char *needle2 = "recindex="; + const size_t needle1_length = strlen(needle1); + const size_t needle2_length = strlen(needle2); + const size_t needle_length = max(needle1_length,needle2_length); + if (data_start + needle_length > data_end) { + return MOBI_SUCCESS; + } + unsigned char *data = (unsigned char *) data_start; + const unsigned char tag_open = '<'; + const unsigned char tag_close = '>'; + unsigned char last_border = tag_open; + while (data <= data_end) { + if (*data == tag_open || *data == tag_close) { + last_border = *data; + } + if (data + needle_length <= data_end && + (memcmp(data, needle1, needle1_length) == 0 || + memcmp(data, needle2, needle2_length) == 0)) { + /* found match */ + if (last_border != tag_open) { + /* opening char not found, not an attribute */ + data += needle_length; + continue; + } + /* go to attribute beginning */ + while (data >= data_start && !isspace(*data) && *data != tag_open) { + data--; + } + result->start = ++data; + /* now go forward */ + int i = 0; + while (data <= data_end && !isspace(*data) && *data != tag_close && i < MOBI_ATTRVALUE_MAXSIZE) { + result->value[i++] = (char) *data++; + } + /* self closing tag '/>' */ + if (data <= data_end && *(data - 1) == '/' && *data == '>') { + --data; --i; + } + result->end = data; + result->value[i] = '\0'; + return MOBI_SUCCESS; + } + data++; + } + return MOBI_SUCCESS; +} + +/** + @brief Find first occurence of markup attribute with given value + + @param[in,out] result MOBIResult structure will be filled with found data + @param[in] data_start Beginning of the memory area to search in + @param[in] data_end End of the memory area to search in + @param[in] type Type of data (T_HTML or T_CSS) + @param[in] needle String to find (len <= MOBI_ATTRNAME_MAXSIZE) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_find_attrvalue(MOBIResult *result, const unsigned char *data_start, const unsigned char *data_end, const MOBIFiletype type, const char *needle) { + if (!result) { + debug_print("Result structure is null%s", "\n"); + return MOBI_PARAM_ERR; + } + result->start = result->end = NULL; + *(result->value) = '\0'; + if (!data_start || !data_end) { + debug_print("Data is null%s", "\n"); + return MOBI_PARAM_ERR; + } + size_t needle_length = strlen(needle); + if (needle_length > MOBI_ATTRNAME_MAXSIZE) { + debug_print("Attribute too long: %zu\n", needle_length); + return MOBI_PARAM_ERR; + } + if (data_start + needle_length > data_end) { + return MOBI_SUCCESS; + } + unsigned char *data = (unsigned char *) data_start; + unsigned char tag_open; + unsigned char tag_close; + if (type == T_CSS) { + tag_open = '{'; + tag_close = '}'; + } else { + tag_open = '<'; + tag_close = '>'; + } + unsigned char last_border = tag_close; + while (data <= data_end) { + if (*data == tag_open || *data == tag_close) { + last_border = *data; + } + if (data + needle_length <= data_end && memcmp(data, needle, needle_length) == 0) { + /* found match */ + if (last_border != tag_open) { + /* opening char not found, not an attribute */ + data += needle_length; + continue; + } + /* go to attribute value beginning */ + while (data >= data_start && !isspace(*data) && *data != tag_open && *data != '=' && *data != '(') { + data--; + } + result->is_url = (*data == '('); + result->start = ++data; + /* now go forward */ + int i = 0; + while (data <= data_end && !isspace(*data) && *data != tag_close && *data != ')' && i < MOBI_ATTRVALUE_MAXSIZE) { + result->value[i++] = (char) *data++; + } + /* self closing tag '/>' */ + if (data <= data_end && *(data - 1) == '/' && *data == '>') { + --data; --i; + } + result->end = data; + result->value[i] = '\0'; + return MOBI_SUCCESS; + } + data++; + } + return MOBI_SUCCESS; +} + +/** + @brief Find first occurence of markup attribute with given name + + @param[in,out] result MOBIResult structure will be filled with found data + @param[in] data_start Beginning of the memory area to search in + @param[in] data_end End of the memory area to search in + @param[in] attrname String to find (len < MOBI_ATTRNAME_MAXSIZE) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_find_attrname(MOBIResult *result, const unsigned char *data_start, const unsigned char *data_end, const char *attrname) { + if (!result) { + debug_print("Result structure is null%s", "\n"); + return MOBI_PARAM_ERR; + } + result->start = result->end = NULL; + *(result->value) = '\0'; + if (!data_start || !data_end) { + debug_print("Data is null%s", "\n"); + return MOBI_PARAM_ERR; + } + char needle[MOBI_ATTRNAME_MAXSIZE + 1]; + snprintf(needle, MOBI_ATTRNAME_MAXSIZE + 1, "%s=", attrname); + size_t needle_length = strlen(needle); + if (data_start + needle_length > data_end) { + return MOBI_SUCCESS; + } + unsigned char *data = (unsigned char *) data_start; + const unsigned char quote = '"'; + const unsigned char tag_open = '<'; + const unsigned char tag_close = '>'; + unsigned char last_border = tag_close; + while (data <= data_end) { + if (*data == tag_open || *data == tag_close) { + last_border = *data; + } + if (data + needle_length + 2 <= data_end && memcmp(data, needle, needle_length) == 0) { + /* found match */ + if (last_border != tag_open) { + /* opening char not found, not an attribute */ + data += needle_length; + continue; + } + /* go to attribute name beginning */ + if (data > data_start) { + data--; + if (!isspace(*data) && *data != tag_open) { + /* wrong name */ + data += needle_length; + continue; + } + } + result->start = ++data; + /* now go forward */ + data += needle_length; + if (*data++ != quote) { + /* not well formed attribute */ + result->start = NULL; + continue; + } + while (data <= data_end) { + if (*data == quote) { + result->end = ++data; + return MOBI_SUCCESS; + } + data++; + } + result->start = NULL; + } + data++; + } + return MOBI_SUCCESS; +} + +/** + @brief Find first occurence of attribute part to be replaced in KF8 html/css + + It searches for "kindle:" value in attributes + + @param[in,out] result MOBIResult structure will be filled with found data + @param[in] data_start Beginning of the memory area to search in + @param[in] data_end End of the memory area to search in + @param[in] type Type of data (T_HTML or T_CSS) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_search_links_kf8(MOBIResult *result, const unsigned char *data_start, const unsigned char *data_end, const MOBIFiletype type) { + return mobi_find_attrvalue(result, data_start, data_end, type, "kindle:"); +} + +/** + @brief Get value and offset of the first found attribute with given name + + @param[in,out] value String value of the attribute, will be filled by the function, zero length if not found + @param[in] data Data to search in + @param[in] size Data size + @param[in] attribute Attribute name + @param[in] only_quoted Require the value to be quoted if true, allow no quotes (eg. filepos=00001) if false + @return Offset from the beginning of the data, SIZE_MAX if not found + */ +size_t mobi_get_attribute_value(char *value, const unsigned char *data, const size_t size, const char *attribute, bool only_quoted) { + /* FIXME: this function could be replaced by mobi_find_attrvalue()? */ + if (!data) { + debug_print("Data is null%s", "\n"); + return SIZE_MAX; + } + size_t length = size; + size_t attr_length = strlen(attribute); + if (attr_length > MOBI_ATTRNAME_MAXSIZE) { + debug_print("Attribute too long: %zu\n", attr_length); + return SIZE_MAX; + } + char attr[MOBI_ATTRNAME_MAXSIZE + 2]; + strcpy(attr, attribute); + strcat(attr, "="); + attr_length++; + if (size < attr_length) { + return SIZE_MAX; + } + /* FIXME: search may start inside tag, so it is a safer option */ + unsigned char last_border = '\0'; + do { + if (*data == '<' || *data == '>') { + last_border = *data; + } + if (length > attr_length + 1 && memcmp(data, attr, attr_length) == 0) { + /* found match */ + size_t offset = size - length; + if (last_border == '>') { + /* We are in tag contents */ + data += attr_length; + length -= attr_length - 1; + continue; + } + /* previous character should be white space or opening tag */ + if (offset > 0) { + if (data[-1] != '<' && !isspace(data[-1])) { + data += attr_length; + length -= attr_length - 1; + continue; + } + } + /* now go forward */ + data += attr_length; + length -= attr_length; + unsigned char separator; + if (*data != '\'' && *data != '"') { + if (only_quoted) { + continue; + } + separator = ' '; + } else { + separator = *data; + data++; + length--; + } + size_t j; + for (j = 0; j < MOBI_ATTRVALUE_MAXSIZE && length && *data != separator && *data != '>'; j++) { + *value++ = (char) *data++; + length--; + } + /* self closing tag '/>' */ + if (length && *(data - 1) == '/' && *data == '>') { + value--; + } + *value = '\0'; + /* return offset to the beginning of the attribute value string */ + return size - length - j; + } + data++; + } while (--length); + value[0] = '\0'; + return SIZE_MAX; +} + +/** + @brief Get offset of the given value of an "aid" attribute in a given part + + @param[in] aid String value of "aid" attribute + @param[in] html MOBIPart html part + @return Offset from the beginning of the html part data, SIZE_MAX on failure + */ +size_t mobi_get_aid_offset(const MOBIPart *html, const char *aid) { + size_t length = html->size; + const char *data = (char *) html->data; + const size_t aid_length = strlen(aid); + const size_t attr_length = 5; /* "aid='" length */ + do { + if (length > (aid_length + attr_length) && memcmp(data, "aid=", attr_length - 1) == 0) { + data += attr_length; + length -= attr_length; + if (memcmp(data, aid, aid_length) == 0) { + if (data[aid_length] == '\'' || data[aid_length] == '"') { + return html->size - length; + } + } + } + data++; + } while (--length); + return SIZE_MAX; +} + +/** + @brief Convert kindle:pos:fid:x:off:y to skeleton part number and offset from the beginning of the part + + @param[in,out] file_number Will be set to file number value + @param[in,out] offset Offset from the beginning of the skeleton part + @param[in] rawml MOBIRawml parsed records structure + @param[in] pos_fid X value of pos:fid:x + @param[in] pos_off X value of pos:off:x + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_offset_by_posoff(uint32_t *file_number, size_t *offset, const MOBIRawml *rawml, const size_t pos_fid, const size_t pos_off) { + if (!rawml || !rawml->frag || !rawml->frag->entries || + !rawml->skel || !rawml->skel->entries) { + debug_print("%s", "Initialization failed\n"); + return MOBI_INIT_FAILED; + } + MOBI_RET ret; + if (pos_fid >= rawml->frag->entries_count) { + debug_print("Entry for pos:fid:%zu doesn't exist\n", pos_fid); + return MOBI_DATA_CORRUPT; + } + const MOBIIndexEntry entry = rawml->frag->entries[pos_fid]; + *offset = strtoul(entry.label, NULL, 10); + uint32_t file_nr; + ret = mobi_get_indxentry_tagvalue(&file_nr, &entry, INDX_TAG_FRAG_FILE_NR); + if (ret != MOBI_SUCCESS) { + return ret; + } + if (file_nr >= rawml->skel->entries_count) { + debug_print("Entry for skeleton part no %u doesn't exist\n", file_nr); + return MOBI_DATA_CORRUPT; + + } + const MOBIIndexEntry skel_entry = rawml->skel->entries[file_nr]; + uint32_t skel_position; + ret = mobi_get_indxentry_tagvalue(&skel_position, &skel_entry, INDX_TAG_SKEL_POSITION); + if (ret != MOBI_SUCCESS) { + return ret; + } + *offset -= skel_position; + *offset += pos_off; + *file_number = file_nr; + return MOBI_SUCCESS; +} + +/** + @brief Get value of the closest "aid" attribute following given offset in a given part + + @param[in,out] aid String value of "aid" attribute + @param[in] html MOBIPart html part + @param[in] offset Offset from the beginning of the part data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_aid_by_offset(char *aid, const MOBIPart *html, const size_t offset) { + if (!aid || !html) { + debug_print("Parameter error (aid (%p), html (%p)\n", (void *) aid, (void *) html); + return MOBI_PARAM_ERR; + } + if (offset > html->size) { + debug_print("Parameter error: offset (%zu) > part size (%zu)\n", offset, html->size); + return MOBI_PARAM_ERR; + } + const unsigned char *data = html->data; + data += offset; + size_t length = html->size - offset; + + size_t off = mobi_get_attribute_value(aid, data, length, "aid", true); + if (off == SIZE_MAX) { + return MOBI_DATA_CORRUPT; + } + return MOBI_SUCCESS; +} + +/** + @brief Get value of the closest "id" or "name" attribute following given offset in a given part + + @param[in,out] id String value of found attribute + @param[in] html MOBIPart html part + @param[in] offset Offset from the beginning of the part data + @param[in,out] pref_attr Preferred attribute to link to (id or name) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_id_by_offset(char *id, const MOBIPart *html, const size_t offset, MOBIAttrType *pref_attr) { + if (!id || !html) { + debug_print("Parameter error (id (%p), html (%p)\n", (void *) id, (void *) html); + return MOBI_PARAM_ERR; + } + if (offset > html->size) { + debug_print("Parameter error: offset (%zu) > part size (%zu)\n", offset, html->size); + return MOBI_PARAM_ERR; + } + const unsigned char *data = html->data; + data += offset; + size_t length = html->size - offset; + static const char * attributes[] = { + [ATTR_ID] = "id", + [ATTR_NAME] = "name", + }; + size_t off = mobi_get_attribute_value(id, data, length, attributes[*pref_attr], true); + if (off == SIZE_MAX) { + // try optional attribute + const MOBIAttrType opt_attr = (*pref_attr == ATTR_ID) ? ATTR_NAME : ATTR_ID; + off = mobi_get_attribute_value(id, data, length, attributes[opt_attr], true); + if (off == SIZE_MAX) { + id[0] = '\0'; + } else { + // save optional attribute as preferred + *pref_attr = opt_attr; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Convert kindle:pos:fid:x:off:y to html file number and closest "aid" attribute following the position + + @param[in,out] file_number Will be set to file number value + @param[in,out] aid String value of "aid" attribute + @param[in] rawml MOBIRawml parsed records structure + @param[in] pos_fid X value of pos:fid:x + @param[in] pos_off Y value of off:y + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_aid_by_posoff(uint32_t *file_number, char *aid, const MOBIRawml *rawml, const size_t pos_fid, const size_t pos_off) { + size_t offset; + MOBI_RET ret = mobi_get_offset_by_posoff(file_number, &offset, rawml, pos_fid, pos_off); + if (ret != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + const MOBIPart *html = mobi_get_part_by_uid(rawml, *file_number); + if (html == NULL) { + return MOBI_DATA_CORRUPT; + } + ret = mobi_get_aid_by_offset(aid, html, offset); + if (ret != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + return MOBI_SUCCESS; +} + +/** + @brief Convert kindle:pos:fid:x:off:y to html file number and closest "id" attribute following the position + + @param[in,out] file_number Will be set to file number value + @param[in,out] id String value of "id" attribute + @param[in] rawml MOBIRawml parsed records structure + @param[in] pos_fid X value of pos:fid:x + @param[in] pos_off Y value of off:y + @param[in,out] pref_attr Attribute to link to + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_id_by_posoff(uint32_t *file_number, char *id, const MOBIRawml *rawml, const size_t pos_fid, const size_t pos_off, MOBIAttrType *pref_attr) { + size_t offset; + MOBI_RET ret = mobi_get_offset_by_posoff(file_number, &offset, rawml, pos_fid, pos_off); + if (ret != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + const MOBIPart *html = mobi_get_part_by_uid(rawml, *file_number); + if (html == NULL) { + return MOBI_DATA_CORRUPT; + } + ret = mobi_get_id_by_offset(id, html, offset, pref_attr); + if (ret != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + return MOBI_SUCCESS; +} + +/** + @brief Parse resource records (images, fonts etc), determine their type, link to rawml + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @param[in,out] rawml Structure rawml->resources will be filled with parsed resources metadata and linked records data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_resources(const MOBIData *m, MOBIRawml *rawml) { + size_t first_res_seqnumber = mobi_get_first_resource_record(m); + if (first_res_seqnumber == MOBI_NOTSET) { + /* search all records */ + first_res_seqnumber = 0; + } + const MOBIPdbRecord *curr_record = mobi_get_record_by_seqnumber(m, first_res_seqnumber); + if (curr_record == NULL) { + debug_print("First resource record not found at %zu, skipping resources\n", first_res_seqnumber); + return MOBI_SUCCESS; + } + size_t i = 0; + MOBIPart *head = NULL; + while (curr_record != NULL) { + const MOBIFiletype filetype = mobi_determine_resource_type(curr_record); + if (filetype == T_UNKNOWN) { + curr_record = curr_record->next; + i++; + continue; + } + if (filetype == T_BREAK) { + break; + } + + MOBIPart *curr_part = calloc(1, sizeof(MOBIPart));; + if (curr_part == NULL) { + debug_print("%s\n", "Memory allocation for flow part failed"); + return MOBI_MALLOC_FAILED; + } + curr_part->data = curr_record->data; + curr_part->size = curr_record->size; + curr_part->uid = i++; + curr_part->next = NULL; + + MOBI_RET ret = MOBI_SUCCESS; + if (filetype == T_FONT) { + ret = mobi_add_font_resource(curr_part); + if (ret != MOBI_SUCCESS) { + debug_print("%s\n", "Decoding font resource failed"); + } + } else if (filetype == T_AUDIO) { + ret = mobi_add_audio_resource(curr_part); + if (ret != MOBI_SUCCESS) { + debug_print("%s\n", "Decoding audio resource failed"); + } + } else if (filetype == T_VIDEO) { + ret = mobi_add_video_resource(curr_part); + if (ret != MOBI_SUCCESS) { + debug_print("%s\n", "Decoding video resource failed"); + } + } else { + curr_part->type = filetype; + } + + curr_record = curr_record->next; + + if (ret != MOBI_SUCCESS) { + free(curr_part); + curr_part = NULL; + } else if (head) { + head->next = curr_part; + head = curr_part; + } else { + rawml->resources = curr_part; + head = curr_part; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Parse Replica Print ebook (azw4). Extract pdf. + @todo Parse remaining data from the file + + @param[in,out] pdf Memory area will be filled with extracted pdf data + @param[in] text Raw decompressed text to be parsed + @param[in,out] length Text length. Will be updated with pdf_length on return + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_process_replica(unsigned char *pdf, const char *text, size_t *length) { + MOBI_RET ret = MOBI_SUCCESS; + MOBIBuffer *buf = mobi_buffer_init_null((unsigned char*) text, *length); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_setpos(buf, 12); + size_t pdf_offset = mobi_buffer_get32(buf); /* offset 12 */ + size_t pdf_length = mobi_buffer_get32(buf); /* 16 */ + if (pdf_length > *length) { + debug_print("PDF size from replica header too large: %zu", pdf_length); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_setpos(buf, pdf_offset); + mobi_buffer_getraw(pdf, buf, pdf_length); + ret = buf->error; + mobi_buffer_free_null(buf); + *length = pdf_length; + return ret; +} + +/** + @brief Parse raw text into flow parts + + @param[in,out] rawml Structure rawml->flow will be filled with parsed flow text parts + @param[in] text Raw decompressed text to be parsed + @param[in] length Text length + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_flow(MOBIRawml *rawml, const char *text, const size_t length) { + /* KF8 */ + if (rawml->fdst != NULL) { + rawml->flow = calloc(1, sizeof(MOBIPart)); + if (rawml->flow == NULL) { + debug_print("%s", "Memory allocation for flow part failed\n"); + return MOBI_MALLOC_FAILED; + } + /* split text into fdst structure parts */ + MOBIPart *curr = rawml->flow; + size_t i = 0; + const size_t section_count = rawml->fdst->fdst_section_count; + while (i < section_count) { + if (i > 0) { + curr->next = calloc(1, sizeof(MOBIPart)); + if (curr->next == NULL) { + debug_print("%s", "Memory allocation for flow part failed\n"); + return MOBI_MALLOC_FAILED; + } + curr = curr->next; + } + const uint32_t section_start = rawml->fdst->fdst_section_starts[i]; + const uint32_t section_end = rawml->fdst->fdst_section_ends[i]; + const size_t section_length = section_end - section_start; + if (section_start + section_length > length) { + debug_print("Wrong fdst section length: %zu\n", section_length); + return MOBI_DATA_CORRUPT; + } + unsigned char *section_data = malloc(section_length); + if (section_data == NULL) { + debug_print("%s", "Memory allocation failed\n"); + return MOBI_MALLOC_FAILED; + } + memcpy(section_data, (text + section_start), section_length); + curr->uid = i; + curr->data = section_data; + curr->type = mobi_determine_flowpart_type(rawml, i); + curr->size = section_length; + curr->next = NULL; + i++; + } + } else { + /* No FDST or FDST parts count = 1 */ + /* single flow part */ + rawml->flow = calloc(1, sizeof(MOBIPart)); + if (rawml->flow == NULL) { + debug_print("%s", "Memory allocation for flow part failed\n"); + return MOBI_MALLOC_FAILED; + } + MOBIPart *curr = rawml->flow; + size_t section_length = 0; + MOBIFiletype section_type = T_HTML; + unsigned char *section_data; + /* check if raw text is Print Replica */ + if (memcmp(text, REPLICA_MAGIC, 4) == 0) { + debug_print("%s", "Print Replica book\n"); + /* print replica */ + unsigned char *pdf = malloc(length); + if (pdf == NULL) { + debug_print("%s", "Memory allocation for flow part failed\n"); + return MOBI_MALLOC_FAILED; + } + section_length = length; + section_type = T_PDF; + const MOBI_RET ret = mobi_process_replica(pdf, text, §ion_length); + if (ret != MOBI_SUCCESS) { + free(pdf); + return ret; + } + section_data = malloc(section_length); + if (section_data == NULL) { + debug_print("%s", "Memory allocation failed\n"); + free(pdf); + return MOBI_MALLOC_FAILED; + } + memcpy(section_data, pdf, section_length); + free(pdf); + } else { + /* text data */ + section_length = length; + section_data = malloc(section_length); + if (section_data == NULL) { + debug_print("%s", "Memory allocation failed\n"); + return MOBI_MALLOC_FAILED; + } + memcpy(section_data, text, section_length); + } + curr->uid = 0; + curr->data = section_data; + curr->type = section_type; + curr->size = section_length; + curr->next = NULL; + } + return MOBI_SUCCESS; +} + +/** + @brief Parse raw html into html parts. Use index entries if present to parse file + + @param[in,out] rawml Structure rawml->markup will be filled with reconstructed html parts + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_parts(MOBIRawml *rawml) { + MOBI_RET ret; + if (rawml->flow == NULL) { + debug_print("%s", "Flow structure not initialized\n"); + return MOBI_INIT_FAILED; + } + /* take first part, xhtml */ + MOBIBuffer *buf = mobi_buffer_init_null(rawml->flow->data, rawml->flow->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + rawml->markup = calloc(1, sizeof(MOBIPart)); + if (rawml->markup == NULL) { + debug_print("%s", "Memory allocation for markup part failed\n"); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + MOBIPart *curr = rawml->markup; + /* not skeleton data, just copy whole part to markup */ + if (rawml->skel == NULL || rawml->skel->entries_count == 0) { + unsigned char *data = malloc(buf->maxlen); + if (data == NULL) { + debug_print("%s", "Memory allocation failed\n"); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + memcpy(data, buf->data, buf->maxlen); + curr->uid = 0; + curr->size = buf->maxlen; + curr->data = data; + curr->type = rawml->flow->type; + curr->next = NULL; + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; + } + if (rawml->frag == NULL) { + debug_print("%s", "Missing frag part\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* parse skeleton data */ + size_t i = 0; + size_t j = 0; + size_t curr_position = 0; + size_t total_fragments_count = rawml->frag->total_entries_count; + while (i < rawml->skel->entries_count) { + const MOBIIndexEntry *entry = &rawml->skel->entries[i]; + uint32_t fragments_count; + ret = mobi_get_indxentry_tagvalue(&fragments_count, entry, INDX_TAG_SKEL_COUNT); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + return ret; + } + if (fragments_count > total_fragments_count) { + debug_print("%s", "Wrong count of fragments\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + total_fragments_count -= fragments_count; + uint32_t skel_position; + ret = mobi_get_indxentry_tagvalue(&skel_position, entry, INDX_TAG_SKEL_POSITION); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + return ret; + } + uint32_t skel_length; + ret = mobi_get_indxentry_tagvalue(&skel_length, entry, INDX_TAG_SKEL_LENGTH); + if (ret != MOBI_SUCCESS || skel_position + skel_length > buf->maxlen) { + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + debug_print("%zu\t%s\t%i\t%i\t%i\n", i, entry->label, fragments_count, skel_position, skel_length); + mobi_buffer_setpos(buf, skel_position); + + unsigned char *frag_buffer = mobi_buffer_getpointer(buf, skel_length); + if (frag_buffer == NULL) { + debug_print("%s\n", "Fragment data beyond buffer"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + MOBIFragment *first_fragment = mobi_list_add(NULL, 0, frag_buffer, skel_length, false); + MOBIFragment *current_fragment = first_fragment; + while (fragments_count--) { + entry = &rawml->frag->entries[j]; + uint32_t insert_position = (uint32_t) strtoul(entry->label, NULL, 10); + if (insert_position < curr_position) { + debug_print("Insert position (%u) before part start (%zu)\n", insert_position, curr_position); + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return MOBI_DATA_CORRUPT; + } + uint32_t file_number; + ret = mobi_get_indxentry_tagvalue(&file_number, entry, INDX_TAG_FRAG_FILE_NR); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return ret; + } + if (file_number != i) { + debug_print("%s", "SKEL part number and fragment sequence number don't match\n"); + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return MOBI_DATA_CORRUPT; + } + uint32_t frag_length; + ret = mobi_get_indxentry_tagvalue(&frag_length, entry, INDX_TAG_FRAG_LENGTH); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return ret; + } +#if (MOBI_DEBUG) + /* FIXME: this fragment metadata is currently unused */ + uint32_t seq_number; + ret = mobi_get_indxentry_tagvalue(&seq_number, entry, INDX_TAG_FRAG_SEQUENCE_NR); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return ret; + } + uint32_t frag_position; + ret = mobi_get_indxentry_tagvalue(&frag_position, entry, INDX_TAG_FRAG_POSITION); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return ret; + } + uint32_t cncx_offset; + ret = mobi_get_indxentry_tagvalue(&cncx_offset, entry, INDX_TAG_FRAG_AID_CNCX); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return ret; + } + const MOBIPdbRecord *cncx_record = rawml->frag->cncx_record; + char *aid_text = mobi_get_cncx_string(cncx_record, cncx_offset); + if (aid_text == NULL) { + mobi_buffer_free_null(buf); + debug_print("%s\n", "Memory allocation failed"); + mobi_list_del_all(first_fragment); + return MOBI_MALLOC_FAILED; + } + debug_print("posfid[%zu]\t%i\t%i\t%s\t%i\t%i\t%i\t%i\n", j, insert_position, cncx_offset, aid_text, file_number, seq_number, frag_position, frag_length); + free(aid_text); +#endif + + insert_position -= curr_position; + if (skel_length < insert_position) { + debug_print("Insert position (%u) after part end (%u)\n", insert_position, skel_length); + /* FIXME: shouldn't the fragment be ignored? */ + /* For now insert it at the end. */ + insert_position = skel_length; + } + + frag_buffer = mobi_buffer_getpointer(buf, frag_length); + if (frag_buffer == NULL) { + debug_print("%s\n", "Fragment data beyond buffer"); + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return MOBI_DATA_CORRUPT; + } + + ret = mobi_list_insert(¤t_fragment, insert_position, frag_buffer, frag_length, false, insert_position); + if (ret == MOBI_SUCCESS) { + skel_length += frag_length; + } else if (ret != MOBI_DATA_CORRUPT) { + /* give up; on data corrupt try to skip broken entry */ + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return ret; + } + j++; + + } + char *skel_text = malloc(skel_length); + if (skel_text == NULL) { + debug_print("%s", "Memory allocation for markup data failed\n"); + mobi_buffer_free_null(buf); + mobi_list_del_all(first_fragment); + return MOBI_MALLOC_FAILED; + } + char *p = skel_text; + while (first_fragment) { + if (first_fragment->fragment) { + memcpy(p, first_fragment->fragment, first_fragment->size); + p += first_fragment->size; + } else { + debug_print("Skipping broken fragment in part %zu\n", i); + } + first_fragment = mobi_list_del(first_fragment); + } + if (i > 0) { + curr->next = calloc(1, sizeof(MOBIPart)); + if (curr->next == NULL) { + debug_print("%s", "Memory allocation for markup part failed\n"); + free(skel_text); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + curr = curr->next; + } + curr->uid = i; + curr->size = skel_length; + curr->data = (unsigned char *) skel_text; + curr->type = T_HTML; + curr->next = NULL; + curr_position += skel_length; + i++; + } + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Scan html part and build array of filepos link target offsets + + @param[in,out] links MOBIArray structure for link target offsets array + @param[in] part MOBIPart html part structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_filepos_array(MOBIArray *links, const MOBIPart *part) { + if (!links || !part) { + return MOBI_INIT_FAILED; + } + size_t offset = 0; + size_t size = part->size; + unsigned char *data = part->data; + while (true) { + char val[MOBI_ATTRVALUE_MAXSIZE + 1]; + size -= offset; + data += offset; + offset = mobi_get_attribute_value(val, data, size, "filepos", false); + if (offset == SIZE_MAX) { break; } + size_t filepos = strtoul(val, NULL, 10); + if (filepos > UINT32_MAX || filepos == 0) { + debug_print("Filepos out of range: %zu\n", filepos); + continue; + } + MOBI_RET ret = array_insert(links, (uint32_t) filepos); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Scan ncx part and build array of filepos link target offsets. + + @param[in,out] links MOBIArray structure for link target offsets array + @param[in] rawml MOBIRawml parsed records structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_ncx_filepos_array(MOBIArray *links, const MOBIRawml *rawml) { + if (!links || !rawml) { + return MOBI_PARAM_ERR; + } + MOBIPart *part = rawml->resources; + while (part) { + if (part->type == T_NCX) { + size_t offset = 0; + size_t size = part->size; + unsigned char *data = part->data; + while (true) { + char val[MOBI_ATTRVALUE_MAXSIZE + 1]; + size -= offset; + data += offset; + offset = mobi_get_attribute_value(val, data, size, "src", false); + if (offset == SIZE_MAX) { break; } + /* part00000.html#0000000000 */ + uint32_t filepos = 0; + sscanf(val + 15, "%10u", &filepos); + MOBI_RET ret = array_insert(links, filepos); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + } + part = part->next; + } + return MOBI_SUCCESS; +} + +/** + @brief Replace kindle:pos link with html href + + @param[in,out] link Memory area which will be filled with "part00000.html#customid", including quotation marks + @param[in] rawml Structure rawml + @param[in] value String kindle:pos:fid:0000:off:0000000000, without quotation marks + @param[in,out] pref_attr Preferred attribute to link to (id or name) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_posfid_to_link(char *link, const MOBIRawml *rawml, const char *value, MOBIAttrType *pref_attr) { + /* "kindle:pos:fid:0000:off:0000000000" */ + /* extract fid and off */ + if (strlen(value) < (sizeof("kindle:pos:fid:0000:off:0000000000") - 1)) { + debug_print("Skipping too short link: %s\n", value); + *link = '\0'; + return MOBI_SUCCESS; + } + value += (sizeof("kindle:pos:fid:") - 1); + if (value[4] != ':') { + debug_print("Skipping malformed link: kindle:pos:fid:%s\n", value); + *link = '\0'; + return MOBI_SUCCESS; + } + char str_fid[4 + 1]; + strncpy(str_fid, value, 4); + str_fid[4] = '\0'; + char str_off[10 + 1]; + value += (sizeof("0001:off:") - 1); + strncpy(str_off, value, 10); + str_off[10] = '\0'; + + /* get file number and id value */ + uint32_t pos_off; + uint32_t pos_fid; + MOBI_RET ret = mobi_base32_decode(&pos_off, str_off); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_base32_decode(&pos_fid, str_fid); + if (ret != MOBI_SUCCESS) { + return ret; + } + uint32_t part_id; + char id[MOBI_ATTRVALUE_MAXSIZE + 1]; + ret = mobi_get_id_by_posoff(&part_id, id, rawml, pos_fid, pos_off, pref_attr); + if (ret != MOBI_SUCCESS) { + return ret; + } + /* FIXME: pos_off == 0 means top of file? */ + if (pos_off) { + int n = snprintf(link, MOBI_ATTRVALUE_MAXSIZE + 1, "\"part%05u.html#%s\"", part_id, id); + if (n > MOBI_ATTRVALUE_MAXSIZE + 1) { + debug_print("Skipping truncated link: %s\n", link); + *link = '\0'; + return MOBI_SUCCESS; + } + } else { + snprintf(link, MOBI_ATTRVALUE_MAXSIZE + 1, "\"part%05u.html\"", part_id); + } + return MOBI_SUCCESS; +} + +/** + @brief Replace kindle:flow link with html href + + @param[in,out] link Memory area which will be filled with "part00000.ext", including quotation marks + @param[in] rawml Structure rawml + @param[in] value String kindle:flow:0000?mime=type, without quotation marks + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_flow_to_link(char *link, const MOBIRawml *rawml, const char *value) { + /* "kindle:flow:0000?mime=" */ + *link = '\0'; + if (strlen(value) < (sizeof("kindle:flow:0000?mime=") - 1)) { + debug_print("Skipping too short link: %s\n", value); + return MOBI_SUCCESS; + } + value += (sizeof("kindle:flow:") - 1); + if (value[4] != '?') { + debug_print("Skipping broken link: kindle:flow:%s\n", value); + return MOBI_SUCCESS; + } + char str_fid[4 + 1]; + strncpy(str_fid, value, 4); + str_fid[4] = '\0'; + + MOBIPart *flow = mobi_get_flow_by_fid(rawml, str_fid); + if (flow == NULL) { + debug_print("Skipping broken link (missing resource): kindle:flow:%s\n", value); + return MOBI_SUCCESS; + } + MOBIFileMeta meta = mobi_get_filemeta_by_type(flow->type); + char *extension = meta.extension; + snprintf(link, MOBI_ATTRVALUE_MAXSIZE + 1, "\"flow%05zu.%s\"", flow->uid, extension); + return MOBI_SUCCESS; +} + +/** + @brief Replace kindle:embed link with html href + + @param[in,out] link Memory area which will be filled with "resource00000.ext", including quotation marks + @param[in] rawml Structure rawml + @param[in] value String kindle:embed:0000?mime=type, with optional quotation marks + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_embed_to_link(char *link, const MOBIRawml *rawml, const char *value) { + /* "kindle:embed:0000[?mime=]" */ + /* skip quotation marks or spaces */ + while (*value == '"' || *value == '\'' || isspace(*value)) { + value++; + } + *link = '\0'; + if (strlen(value) < (sizeof("kindle:embed:0000") - 1)) { + debug_print("Skipping too short link: %s\n", value); + return MOBI_SUCCESS; + } + value += (sizeof("kindle:embed:") - 1); + char str_fid[4 + 1]; + strncpy(str_fid, value, 4); + str_fid[4] = '\0'; + + /* get file number */ + uint32_t part_id; + MOBI_RET ret = mobi_base32_decode(&part_id, str_fid); + if (ret != MOBI_SUCCESS) { + debug_print("Skipping broken link (corrupt base32): kindle:embed:%s\n", value); + return MOBI_SUCCESS; + } + part_id--; + MOBIPart *resource = mobi_get_resource_by_uid(rawml, part_id); + if (resource == NULL) { + debug_print("Skipping broken link (missing resource): kindle:embed:%s\n", value); + return MOBI_SUCCESS; + } + MOBIFileMeta meta = mobi_get_filemeta_by_type(resource->type); + char *extension = meta.extension; + snprintf(link, MOBI_ATTRVALUE_MAXSIZE + 1, "\"resource%05u.%s\"", part_id, extension); + return MOBI_SUCCESS; +} + +/** + @brief Replace offset-links with html-links in KF8 markup + + @param[in,out] rawml Structure rawml will be filled with reconstructed parts and resources + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_links_kf8(const MOBIRawml *rawml) { + MOBIResult result; + + typedef struct NEWData { + size_t part_group; + size_t part_uid; + MOBIFragment *list; + size_t size; + struct NEWData *next; + } NEWData; + + NEWData *partdata = NULL; + NEWData *curdata = NULL; + MOBIPart *parts[] = { + rawml->markup, /* html files */ + rawml->flow->next /* css, skip first unparsed html part */ + }; + size_t i; + for (i = 0; i < 2; i++) { + MOBIPart *part = parts[i]; + while (part) { + if (part->data == NULL || part->size == 0) { + debug_print("Skipping empty part%s", "\n"); + part = part->next; + continue; + } + unsigned char *data_in = part->data; + result.start = part->data; + const unsigned char *data_end = part->data + part->size - 1; + MOBIFragment *first = NULL; + MOBIFragment *curr = NULL; + size_t part_size = 0; + MOBIAttrType pref_attr = ATTR_ID; + while (true) { + mobi_search_links_kf8(&result, result.start, data_end, part->type); + if (result.start == NULL) { + break; + } + char *value = (char *) result.value; + unsigned char *data_cur = result.start; + char *target = NULL; + if (data_cur < data_in) { + mobi_list_del_all(first); + return MOBI_DATA_CORRUPT; + } + size_t size = (size_t) (data_cur - data_in); + char link[MOBI_ATTRVALUE_MAXSIZE + 1]; + if ((target = strstr(value, "kindle:pos:fid:")) != NULL) { + /* "kindle:pos:fid:0001:off:0000000000" */ + /* replace link with href="part00000.html#00" */ + /* FIXME: this requires present target id or name attribute */ + MOBI_RET ret = mobi_posfid_to_link(link, rawml, target, &pref_attr); + if (ret != MOBI_SUCCESS) { + mobi_list_del_all(first); + return ret; + } + } else if ((target = strstr(value, "kindle:flow:")) != NULL) { + /* kindle:flow:0000?mime=text/css */ + /* replace link with href="flow00000.ext" */ + MOBI_RET ret = mobi_flow_to_link(link, rawml, target); + if (ret != MOBI_SUCCESS) { + mobi_list_del_all(first); + return ret; + } + } else if ((target = strstr(value, "kindle:embed:")) != NULL) { + /* kindle:embed:0000?mime=image/jpg */ + /* kindle:embed:0000 (font resources) */ + /* replace link with href="resource00000.ext" */ + MOBI_RET ret = mobi_embed_to_link(link, rawml, target); + if (ret != MOBI_SUCCESS) { + mobi_list_del_all(first); + return ret; + } + } + if (target && *link != '\0') { + /* first chunk */ + curr = mobi_list_add(curr, (size_t) (data_in - part->data), data_in, size, false); + if (curr == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (!first) { first = curr; } + part_size += curr->size; + /* second chunk */ + /* strip quotes if is_url */ + curr = mobi_list_add(curr, SIZE_MAX, + (unsigned char *) strdup(link + result.is_url), + strlen(link) - 2 * result.is_url, true); + if (curr == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + part_size += curr->size; + data_in = result.end; + } + } + if (first && first->fragment) { + /* last chunk */ + if (part->data + part->size < data_in) { + mobi_list_del_all(first); + return MOBI_DATA_CORRUPT; + } + size_t size = (size_t) (part->data + part->size - data_in); + curr = mobi_list_add(curr, (size_t) (data_in - part->data), data_in, size, false); + if (curr == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + part_size += curr->size; + /* save */ + if (!curdata) { + curdata = calloc(1, sizeof(NEWData)); + partdata = curdata; + } else { + curdata->next = calloc(1, sizeof(NEWData)); + curdata = curdata->next; + } + curdata->part_group = i; + curdata->part_uid = part->uid; + curdata->list = first; + curdata->size = part_size; + } + part = part->next; + } + } + /* now update parts */ + debug_print("Inserting links%s", "\n"); + for (i = 0; i < 2; i++) { + MOBIPart *part = parts[i]; + while (part) { + if (partdata && part->uid == partdata->part_uid && i == partdata->part_group) { + MOBIFragment *fragdata = partdata->list; + unsigned char *new_data = malloc(partdata->size); + if (new_data == NULL) { + mobi_list_del_all(fragdata); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + unsigned char *data_out = new_data; + while (fragdata) { + memcpy(data_out, fragdata->fragment, fragdata->size); + data_out += fragdata->size; + fragdata = mobi_list_del(fragdata); + } + free(part->data); + part->data = new_data; + part->size = partdata->size; + NEWData *partused = partdata; + partdata = partdata->next; + free(partused); + } + part = part->next; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Get infl index markup for given orth entry + + @param[in,out] outstring Reconstructed tag + @param[in] infl MOBIIndx structure with parsed infl index + @param[in] orth_entry Orth index entry + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_infl(char *outstring, const MOBIIndx *infl, const MOBIIndexEntry *orth_entry) { + const char *label = orth_entry->label; + uint32_t *infl_groups = NULL; + size_t infl_count = mobi_get_indxentry_tagarray(&infl_groups, orth_entry, INDX_TAGARR_ORTH_INFL); + + if (infl_count == 0 || !infl_groups) { + return MOBI_SUCCESS; + } + const char *start_tag = ""; + const char *end_tag = ""; + const char *iform_tag = ""; + char name_attr[INDX_INFLBUF_SIZEMAX + 1]; + char infl_tag[INDX_INFLBUF_SIZEMAX + 1]; + strcpy(outstring, start_tag); + size_t initlen = strlen(start_tag) + strlen(end_tag); + size_t outlen = initlen; + size_t label_length = strlen(label); + if (label_length > INDX_INFLBUF_SIZEMAX) { + debug_print("Entry label too long (%s)\n", label); + return MOBI_DATA_CORRUPT; + } + if (infl->cncx_record == NULL) { + debug_print("%s\n", "Missing cncx record"); + return MOBI_DATA_CORRUPT; + } + for (size_t i = 0; i < infl_count; i++) { + size_t offset = infl_groups[i]; + if (offset >= infl->entries_count) { + debug_print("%s\n", "Invalid entry offset"); + return MOBI_DATA_CORRUPT; + } + uint32_t *groups; + size_t group_cnt = mobi_get_indxentry_tagarray(&groups, &infl->entries[offset], INDX_TAGARR_INFL_GROUPS); + uint32_t *parts; + size_t part_cnt = mobi_get_indxentry_tagarray(&parts, &infl->entries[offset], INDX_TAGARR_INFL_PARTS_V2); + if (group_cnt != part_cnt) { + return MOBI_DATA_CORRUPT; + } + for (size_t j = 0; j < part_cnt; j++) { + name_attr[0] = '\0'; + char *group_name = mobi_get_cncx_string(infl->cncx_record, groups[j]); + if (group_name == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (strlen(group_name)) { + snprintf(name_attr, INDX_INFLBUF_SIZEMAX, " name=\"%s\"", group_name); + } + free(group_name); + + unsigned char decoded[INDX_INFLBUF_SIZEMAX + 1]; + memset(decoded, 0, INDX_INFLBUF_SIZEMAX + 1); + if (parts[j] >= infl->entries_count) { + debug_print("%s\n", "Invalid entry offset"); + return MOBI_DATA_CORRUPT; + } + unsigned char *rule = (unsigned char *) infl->entries[parts[j]].label; + memcpy(decoded, label, label_length); + int decoded_length = (int) label_length; + MOBI_RET ret = mobi_decode_infl(decoded, &decoded_length, rule); + if (ret != MOBI_SUCCESS) { + return ret; + } + if (decoded_length == 0) { + continue; + } + int n = snprintf(infl_tag, INDX_INFLBUF_SIZEMAX, iform_tag, name_attr, decoded); + if (n > INDX_INFLBUF_SIZEMAX) { + debug_print("Skipping truncated tag: %s\n", infl_tag); + continue; + } + outlen += strlen(infl_tag); + if (outlen > INDX_INFLTAG_SIZEMAX) { + debug_print("Inflections text in %s too long (%zu)\n", label, outlen); + return MOBI_ERROR; + } + strcat(outstring, infl_tag); + } + } + if (outlen == initlen) { + outstring[0] = '\0'; + } else { + strcat(outstring, end_tag); + } + return MOBI_SUCCESS; +} + +/** + @brief Get infl index markup for given orth entry + + This function is inflections scheme used in older mobipocket dictionaries + + @param[in,out] outstring Reconstructed tag + @param[in] infl_tree MOBITrie structure with inflection rules + @param[in] orth_entry Orth index entry + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_infl_v1(char *outstring, MOBITrie * const infl_tree, const MOBIIndexEntry *orth_entry) { + const char *label = orth_entry->label; + const size_t label_length = strlen(label); + if (label_length > INDX_INFLBUF_SIZEMAX) { + debug_print("Entry label too long (%s)\n", label); + return MOBI_DATA_CORRUPT; + } + char *infl_strings[INDX_INFLSTRINGS_MAX]; + size_t infl_count = mobi_trie_get_inflgroups(infl_strings, infl_tree, label); + + if (infl_count == 0) { + return MOBI_SUCCESS; + } + + const char *start_tag = ""; + const char *end_tag = ""; + const char *iform_tag = ""; + char infl_tag[INDX_INFLBUF_SIZEMAX + 1]; + strcpy(outstring, start_tag); + size_t initlen = strlen(start_tag) + strlen(end_tag); + size_t outlen = initlen; + for (size_t i = 0; i < infl_count; i++) { + char *decoded = infl_strings[i]; + size_t decoded_length = strlen(decoded); + + if (decoded_length == 0) { + free(decoded); + continue; + } + int n = snprintf(infl_tag, INDX_INFLBUF_SIZEMAX, iform_tag, decoded); + /* allocated in mobi_trie_get_inflgroups() */ + free(decoded); + if (n > INDX_INFLBUF_SIZEMAX) { + debug_print("Skipping too long tag: %s\n", infl_tag); + continue; + } + outlen += strlen(infl_tag); + if (outlen > INDX_INFLTAG_SIZEMAX) { + debug_print("Inflections text in %s too long (%zu)\n", label, outlen); + break; + } + strcat(outstring, infl_tag); + } + if (outlen == initlen) { + outstring[0] = '\0'; + } else { + strcat(outstring, end_tag); + } + return MOBI_SUCCESS; +} + +/** + @brief Insert orth index markup to linked list of fragments + + @param[in] rawml Structure rawml contains orth index data + @param[in,out] first First element of the linked list + @param[in,out] new_size Counter to be updated with inserted fragments size + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_orth(const MOBIRawml *rawml, MOBIFragment *first, size_t *new_size) { + MOBITrie *infl_trie = NULL; + bool is_infl_v2 = mobi_indx_has_tag(rawml->orth, INDX_TAGARR_ORTH_INFL); + bool is_infl_v1 = false; + if (is_infl_v2 == false) { + is_infl_v1 = mobi_indx_has_tag(rawml->infl, INDX_TAGARR_INFL_PARTS_V1); + } + debug_print("Reconstructing orth index %s\n", (is_infl_v1)?"(infl v1)":(is_infl_v2)?"(infl v2)":""); + if (is_infl_v1) { + size_t total = rawml->infl->entries_count; + size_t j = 0; + while (j < total) { + MOBI_RET ret = mobi_trie_insert_infl(&infl_trie, rawml->infl, j++); + if (ret != MOBI_SUCCESS || infl_trie == NULL) { + debug_print("Building trie for inflections failed%s", "\n"); + mobi_trie_free(infl_trie); + is_infl_v1 = false; + } + } + } + + MOBIFragment *curr = first; + size_t i = 0; + const size_t count = rawml->orth->entries_count; + const char *start_tag1 = "%s"; + const char *start_tag2 = "%s"; + const char *end_tag = ""; + const size_t start_tag1_len = strlen(start_tag1) - 4; + const size_t start_tag2_len = strlen(start_tag2) - 4; + const size_t end_tag_len = strlen(end_tag); + uint32_t prev_startpos = 0; + while (i < count) { + const MOBIIndexEntry *orth_entry = &rawml->orth->entries[i]; + const char *label = orth_entry->label; + uint32_t entry_startpos; + MOBI_RET ret = mobi_get_indxentry_tagvalue(&entry_startpos, orth_entry, INDX_TAG_ORTH_POSITION); + if (ret != MOBI_SUCCESS) { + i++; + continue; + } + size_t entry_length = 0; + uint32_t entry_textlen = 0; + mobi_get_indxentry_tagvalue(&entry_textlen, orth_entry, INDX_TAG_ORTH_LENGTH); + char *start_tag; + if (entry_textlen == 0) { + entry_length += start_tag1_len + strlen(label); + start_tag = (char *) start_tag1; + } else { + entry_length += start_tag2_len + strlen(label); + start_tag = (char *) start_tag2; + } + + char *entry_text; + if (rawml->infl) { + char *infl_tag = malloc(INDX_INFLTAG_SIZEMAX + 1); + if (infl_tag == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_trie_free(infl_trie); + return MOBI_MALLOC_FAILED; + } + infl_tag[0] = '\0'; + if (is_infl_v2) { + ret = mobi_reconstruct_infl(infl_tag, rawml->infl, orth_entry); + } else if (is_infl_v1) { + ret = mobi_reconstruct_infl_v1(infl_tag, infl_trie, orth_entry); + } else { + debug_print("Unknown inflection scheme?%s", "\n"); + } + if (ret != MOBI_SUCCESS) { + free(infl_tag); + return ret; + } + entry_length += strlen(infl_tag); + + entry_text = malloc(entry_length + 1); + if (entry_text == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_trie_free(infl_trie); + free(infl_tag); + return MOBI_MALLOC_FAILED; + } + snprintf(entry_text, entry_length + 1, start_tag, label, infl_tag); + free(infl_tag); + } else { + entry_text = malloc(entry_length + 1); + if (entry_text == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_trie_free(infl_trie); + return MOBI_MALLOC_FAILED; + } + snprintf(entry_text, entry_length + 1, start_tag, label, ""); + } + + if (entry_startpos < prev_startpos) { + curr = first; + } + + ret = mobi_list_insert(&curr, SIZE_MAX, + (unsigned char *) entry_text, + entry_length, true, entry_startpos); + prev_startpos = entry_startpos; + + if (ret == MOBI_SUCCESS) { + *new_size += curr->size; + if (entry_textlen > 0) { + /* FIXME: avoid end_tag duplication */ + ret = mobi_list_insert(&curr, SIZE_MAX, + (unsigned char *) strdup(end_tag), + end_tag_len, true, entry_startpos + entry_textlen); + if (ret == MOBI_SUCCESS) { + *new_size += curr->size; + } else if (ret != MOBI_DATA_CORRUPT) { + mobi_trie_free(infl_trie); + return ret; + } + + } + } else if (ret != MOBI_DATA_CORRUPT) { + /* give up; on data corrupt try to skip broken entry */ + mobi_trie_free(infl_trie); + return ret; + } + i++; + } + mobi_trie_free(infl_trie); + return MOBI_SUCCESS; +} + +/** + @brief Replace offset-links with html-links in KF7 markup. + Also reconstruct dictionary markup if present + + @param[in,out] rawml Structure rawml will be filled with reconstructed parts and resources + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_links_kf7(const MOBIRawml *rawml) { + MOBIResult result; + MOBIArray *links = array_init(25); + if (links == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBIPart *part = rawml->markup; + /* get array of link target offsets */ + MOBI_RET ret = mobi_get_filepos_array(links, part); + if (ret != MOBI_SUCCESS) { + array_free(links); + return ret; + } + ret = mobi_get_ncx_filepos_array(links, rawml); + if (ret != MOBI_SUCCESS) { + array_free(links); + return ret; + } + array_sort(links, true); + unsigned char *data_in = part->data; + MOBIFragment *first = NULL; + MOBIFragment *curr = NULL; + size_t new_size = 0; + /* build MOBIResult list */ + result.start = part->data; + const unsigned char *data_end = part->data + part->size - 1; + while (true) { + mobi_search_links_kf7(&result, result.start, data_end); + if (result.start == NULL) { + break; + } + char *attribute = (char *) result.value; + unsigned char *data_cur = result.start; + result.start = result.end; + char link[MOBI_ATTRVALUE_MAXSIZE + 1]; + const char *numbers = "0123456789"; + char *value = strpbrk(attribute, numbers); + if (value == NULL) { + debug_print("Unknown link target: %s\n", attribute); + continue; + } + size_t target; + switch (attribute[0]) { + case 'f': + /* filepos=0000000000 */ + /* replace link with href="#0000000000" */ + target = strtoul(value, NULL, 10); + snprintf(link, MOBI_ATTRVALUE_MAXSIZE + 1, "href=\"#%010u\"", (uint32_t)target); + break; + case 'h': + case 'l': + data_cur += 2; + /* falls through */ + case 'r': + /* (hi|lo)recindex="00000" */ + /* replace link with src="resource00000.ext" */ + target = strtoul(value, NULL, 10); + if (target > 0) { + target--; + } + MOBIFiletype filetype = mobi_get_resourcetype_by_uid(rawml, target); + MOBIFileMeta filemeta = mobi_get_filemeta_by_type(filetype); + snprintf(link, MOBI_ATTRVALUE_MAXSIZE + 1, "src=\"resource%05u.%s\"", (uint32_t) target, filemeta.extension); + break; + default: + debug_print("Unknown link target: %s\n", attribute); + continue; + } + + /* first chunk */ + if (data_cur < data_in) { + mobi_list_del_all(first); + array_free(links); + return MOBI_DATA_CORRUPT; + } + size_t size = (size_t) (data_cur - data_in); + size_t raw_offset = (size_t) (data_in - part->data); + curr = mobi_list_add(curr, raw_offset, data_in, size, false); + if (curr == NULL) { + mobi_list_del_all(first); + array_free(links); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (!first) { first = curr; } + new_size += curr->size; + /* second chunk */ + curr = mobi_list_add(curr, SIZE_MAX, + (unsigned char *) strdup(link), + strlen(link), true); + if (curr == NULL) { + mobi_list_del_all(first); + array_free(links); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + new_size += curr->size; + data_in = result.end; + } + if (first) { + /* last chunk */ + if (part->data + part->size < data_in) { + mobi_list_del_all(first); + array_free(links); + return MOBI_DATA_CORRUPT; + } + size_t size = (size_t) (part->data + part->size - data_in); + size_t raw_offset = (size_t) (data_in - part->data); + curr = mobi_list_add(curr, raw_offset, data_in, size, false); + if (curr == NULL) { + mobi_list_del_all(first); + array_free(links); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + new_size += curr->size; + } else { + /* add whole part as one fragment */ + first = mobi_list_add(first, 0, part->data, part->size, false); + if (first == NULL) { + array_free(links); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + new_size += first->size; + } + /* insert chunks from links array */ + curr = first; + size_t i = 0; + while (i < links->size) { + const uint32_t offset = links->data[i]; + char anchor[MOBI_ATTRVALUE_MAXSIZE + 1]; + snprintf(anchor, MOBI_ATTRVALUE_MAXSIZE + 1, "", offset); + + ret = mobi_list_insert(&curr, SIZE_MAX, + (unsigned char *) strdup(anchor), + strlen(anchor), true, offset); + if (ret == MOBI_SUCCESS) { + new_size += curr->size; + } else if (ret != MOBI_DATA_CORRUPT) { + /* give up; on data corrupt try to skip broken entry */ + mobi_list_del_all(first); + array_free(links); + return ret; + } + + i++; + } + array_free(links); + /* insert dictionary markup if present */ + if (rawml->orth) { + ret = mobi_reconstruct_orth(rawml, first, &new_size); + if (ret != MOBI_SUCCESS) { + mobi_list_del_all(first); + return ret; + } + } + if (first && first->next) { + /* save */ + debug_print("Inserting links%s", "\n"); + unsigned char *new_data = malloc(new_size); + if (new_data == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + unsigned char *data_out = new_data; + MOBIFragment *fragdata = first; + while (fragdata) { + memcpy(data_out, fragdata->fragment, fragdata->size); + data_out += fragdata->size; + fragdata = mobi_list_del(fragdata); + } + free(part->data); + part->data = new_data; + part->size = new_size; + } else { + mobi_list_del(first); + } + return MOBI_SUCCESS; +} + +/** + @brief Replace offset-links with html-links + + @param[in,out] rawml Structure rawml will be filled with reconstructed parts and resources + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_reconstruct_links(const MOBIRawml *rawml) { + debug_print("Reconstructing links%s", "\n"); + if (rawml == NULL) { + debug_print("%s\n", "Rawml not initialized\n"); + return MOBI_INIT_FAILED; + } + MOBI_RET ret; + if (mobi_is_rawml_kf8(rawml)) { + /* kf8 gymnastics */ + ret = mobi_reconstruct_links_kf8(rawml); + } else { + /* kf7 format and older */ + ret = mobi_reconstruct_links_kf7(rawml); + } + return ret; +} + +/** + @brief Call callback function for each text record + + @param[in,out] rawml Structure rawml will be filled with reconstructed parts and resources + @param[in,out] cb Callback function + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_iterate_txtparts(MOBIRawml *rawml, MOBI_RET (*cb) (MOBIPart *)) { + MOBIPart *parts[] = { + rawml->markup, /* html files */ + rawml->flow->next /* css, skip first unparsed html part */ + }; + size_t i; + for (i = 0; i < 2; i++) { + MOBIPart *part = parts[i]; + while (part) { + if (part->type == T_HTML || part->type == T_CSS) { + MOBI_RET ret = cb(part); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + part = part->next; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Convert MOBIPart part data to utf8 + + @param[in,out] part MOBIPart part + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_markup_to_utf8(MOBIPart *part) { + if (part == NULL) { + return MOBI_INIT_FAILED; + } + unsigned char *text = part->data; + size_t length = part->size; + /* extreme case in which each input character is converted + to 3-byte utf-8 sequence */ + size_t out_length = 3 * length + 1; + char *out_text = malloc(out_length); + if (out_text == NULL) { + debug_print("%s", "Memory allocation failed\n"); + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = mobi_cp1252_to_utf8(out_text, (const char *) text, &out_length, length); + free(text); + if (ret != MOBI_SUCCESS || out_length == 0) { + debug_print("%s", "conversion from cp1252 to utf8 failed\n"); + free(out_text); + part->data = NULL; + return MOBI_DATA_CORRUPT; + } + text = malloc(out_length); + if (text == NULL) { + debug_print("%s", "Memory allocation failed\n"); + free(out_text); + part->data = NULL; + return MOBI_MALLOC_FAILED; + } + memcpy(text, out_text, out_length); + free(out_text); + part->data = text; + part->size = out_length; + return MOBI_SUCCESS; +} + +/** + @brief Strip unneeded tags from html. Currently only + + @param[in,out] part MOBIPart structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_strip_mobitags(MOBIPart *part) { + if (part == NULL || part->data == NULL) { + return MOBI_INIT_FAILED; + } + if (part->type != T_HTML) { + return MOBI_SUCCESS; + } + MOBIResult result; + unsigned char *data_in = part->data; + result.start = part->data; + const unsigned char *data_end = part->data + part->size - 1; + MOBIFragment *first = NULL; + MOBIFragment *curr = NULL; + size_t part_size = 0; + while (true) { + mobi_find_attrname(&result, result.start, data_end, "aid"); + if (result.start == NULL) { + break; + } + unsigned char *data_cur = result.start; + result.start = result.end; + if (data_cur < data_in) { + mobi_list_del_all(first); + return MOBI_DATA_CORRUPT; + } + size_t size = (size_t) (data_cur - data_in); + /* first chunk */ + curr = mobi_list_add(curr, (size_t) (data_in - part->data ), data_in, size, false); + if (curr == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + if (!first) { first = curr; } + part_size += curr->size; + data_in = result.end; + } + if (first) { + /* last chunk */ + if (part->data + part->size < data_in) { + mobi_list_del_all(first); + return MOBI_DATA_CORRUPT; + } + size_t size = (size_t) (part->data + part->size - data_in); + curr = mobi_list_add(curr, (size_t) (data_in - part->data ), data_in, size, false); + if (curr == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + part_size += curr->size; + + unsigned char *new_data = malloc(part_size); + if (new_data == NULL) { + mobi_list_del_all(first); + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + unsigned char *data_out = new_data; + while (first) { + memcpy(data_out, first->fragment, first->size); + data_out += first->size; + first = mobi_list_del(first); + } + free(part->data); + part->data = new_data; + part->size = part_size; + } + return MOBI_SUCCESS; +} + +/** + @brief Parse raw records into html flow parts, markup parts, resources and indices + + @param[in,out] rawml Structure rawml will be filled with reconstructed parts and resources + @param[in] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_rawml(MOBIRawml *rawml, const MOBIData *m) { + return mobi_parse_rawml_opt(rawml, m, true, true, true); +} + +/** + @brief Parse raw records into html flow parts, markup parts, resources and indices. + Individual stages of the parsing may be turned on/off. + + @param[in,out] rawml Structure rawml will be filled with reconstructed parts and resources + @param[in] m MOBIData structure + @param[in] parse_toc bool Parse content indices if true + @param[in] parse_dict bool Parse dictionary indices if true + @param[in] reconstruct bool Recounstruct links, build opf, strip mobi-specific tags if true + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_rawml_opt(MOBIRawml *rawml, const MOBIData *m, bool parse_toc, bool parse_dict, bool reconstruct) { + + MOBI_RET ret; + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (rawml == NULL) { + return MOBI_INIT_FAILED; + } + + /* Get maximal size of text data */ + const size_t maxlen = mobi_get_text_maxsize(m); + if (maxlen == MOBI_NOTSET) { + debug_print("%s", "Insane text length\n"); + return MOBI_DATA_CORRUPT; + } + char *text = malloc(maxlen + 1); + if (text == NULL) { + debug_print("%s", "Memory allocation failed\n"); + return MOBI_MALLOC_FAILED; + } + /* Extract text records, unpack, merge and copy it to text string */ + size_t length = maxlen; + ret = mobi_get_rawml(m, text, &length); + if (ret != MOBI_SUCCESS) { + debug_print("%s", "Error parsing text\n"); + free(text); + return ret; + } + + if (mobi_exists_fdst(m)) { + /* Skip parsing if section count less or equal than 1 */ + if (m->mh->fdst_section_count && *m->mh->fdst_section_count > 1) { + ret = mobi_parse_fdst(m, rawml); + if (ret != MOBI_SUCCESS) { + free(text); + return ret; + } + } + } + ret = mobi_reconstruct_flow(rawml, text, length); + free(text); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_reconstruct_resources(m, rawml); + if (ret != MOBI_SUCCESS) { + return ret; + } + const size_t offset = mobi_get_kf8offset(m); + /* skeleton index */ + if (mobi_exists_skel_indx(m) && mobi_exists_frag_indx(m)) { + const size_t indx_record_number = *m->mh->skeleton_index + offset; + /* to be freed in mobi_free_rawml */ + MOBIIndx *skel_meta = mobi_init_indx(); + ret = mobi_parse_index(m, skel_meta, indx_record_number); + if (ret != MOBI_SUCCESS) { + return ret; + } + rawml->skel = skel_meta; + } + + /* fragment index */ + if (mobi_exists_frag_indx(m)) { + MOBIIndx *frag_meta = mobi_init_indx(); + const size_t indx_record_number = *m->mh->fragment_index + offset; + ret = mobi_parse_index(m, frag_meta, indx_record_number); + if (ret != MOBI_SUCCESS) { + return ret; + } + rawml->frag = frag_meta; + } + + if (parse_toc) { + /* guide index */ + if (mobi_exists_guide_indx(m)) { + MOBIIndx *guide_meta = mobi_init_indx(); + const size_t indx_record_number = *m->mh->guide_index + offset; + ret = mobi_parse_index(m, guide_meta, indx_record_number); + if (ret != MOBI_SUCCESS) { + return ret; + } + rawml->guide = guide_meta; + } + + /* ncx index */ + if (mobi_exists_ncx(m)) { + MOBIIndx *ncx_meta = mobi_init_indx(); + const size_t indx_record_number = *m->mh->ncx_index + offset; + ret = mobi_parse_index(m, ncx_meta, indx_record_number); + if (ret != MOBI_SUCCESS) { + return ret; + } + rawml->ncx = ncx_meta; + } + } + + if (parse_dict && mobi_is_dictionary(m)) { + /* orth */ + MOBIIndx *orth_meta = mobi_init_indx(); + size_t indx_record_number = *m->mh->orth_index + offset; + ret = mobi_parse_index(m, orth_meta, indx_record_number); + if (ret != MOBI_SUCCESS) { + return ret; + } + rawml->orth = orth_meta; + /* infl */ + if (mobi_exists_infl(m)) { + MOBIIndx *infl_meta = mobi_init_indx(); + indx_record_number = *m->mh->infl_index + offset; + ret = mobi_parse_index(m, infl_meta, indx_record_number); + if (ret != MOBI_SUCCESS) { + return ret; + } + rawml->infl = infl_meta; + } + } + + ret = mobi_reconstruct_parts(rawml); + if (ret != MOBI_SUCCESS) { + return ret; + } + if (reconstruct) { +#ifdef USE_XMLWRITER + ret = mobi_build_opf(rawml, m); + if (ret != MOBI_SUCCESS) { + return ret; + } +#endif + ret = mobi_reconstruct_links(rawml); + if (ret != MOBI_SUCCESS) { + return ret; + } + if (mobi_is_kf8(m)) { + debug_print("Stripping unneeded tags%s", "\n"); + ret = mobi_iterate_txtparts(rawml, mobi_strip_mobitags); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + + } + if (mobi_is_cp1252(m)) { + debug_print("Converting cp1252 to utf8%s", "\n"); + ret = mobi_iterate_txtparts(rawml, mobi_markup_to_utf8); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + return MOBI_SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/parse_rawml.h b/Charcoal/Charcoal/libmobi-public/src/parse_rawml.h new file mode 100644 index 0000000..6d698ff --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/parse_rawml.h @@ -0,0 +1,42 @@ +/** @file parse_rawml.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_parse_rawml_h +#define mobi_parse_rawml_h + +#include "config.h" +#include "mobi.h" + +#define MOBI_ATTRNAME_MAXSIZE 150 /**< Maximum length of tag attribute name, like "href" */ +#define MOBI_ATTRVALUE_MAXSIZE 150 /**< Maximum length of tag attribute value */ + +/** + @brief Result data returned by mobi_search_links_kf7() and mobi_search_links_kf8() + */ +typedef struct { + unsigned char *start; /**< Beginning data to be replaced */ + unsigned char *end; /**< End of data to be replaced */ + char value[MOBI_ATTRVALUE_MAXSIZE + 1]; /**< Attribute value */ + bool is_url; /**< True if value is part of css url attribute */ +} MOBIResult; + +/** + @brief HTML attribute type + */ +typedef enum { + ATTR_ID = 0, /**< Attribute 'id' */ + ATTR_NAME /**< Attribute 'name' */ +} MOBIAttrType; + + +MOBI_RET mobi_get_id_by_posoff(uint32_t *file_number, char *id, const MOBIRawml *rawml, const size_t pos_fid, const size_t pos_off, MOBIAttrType *pref_attr); +MOBI_RET mobi_find_attrvalue(MOBIResult *result, const unsigned char *data_start, const unsigned char *data_end, const MOBIFiletype type, const char *needle); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/randombytes.c b/Charcoal/Charcoal/libmobi-public/src/randombytes.c new file mode 100644 index 0000000..0f97106 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/randombytes.c @@ -0,0 +1,375 @@ +/** @file randombytes.c + * @brief Portable function for generating random data + * + * Copyright (c) 2022 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + * + * This code is based on libsodium's randombytes_buf function + * We just extract the single function we need from libsodium and adjust it for our use. + * Most of the code originates from: + * https://github.com/jedisct1/libsodium/blob/d250858c7445b7de94e912b529b81defe20d4aaa/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c + * Original code uses following license: + * + * ISC License + * + * Copyright (c) 2013-2022 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +#endif +#include + +#include "config.h" +#include "randombytes.h" +#include "debug.h" + +#include +#ifndef _WIN32 +# include +# include +#endif +#ifdef __linux__ +# define _LINUX_SOURCE +#endif +#ifdef HAVE_SYS_RANDOM_H +# include +#endif +#ifdef __linux__ +# define BLOCK_ON_DEV_RANDOM +# include +# ifdef HAVE_GETRANDOM +# define HAVE_LINUX_COMPATIBLE_GETRANDOM +# else +# include +# if defined(SYS_getrandom) && defined(__NR_getrandom) +# define getrandom(B, S, F) syscall(SYS_getrandom, (B), (int) (S), (F)) +# define HAVE_LINUX_COMPATIBLE_GETRANDOM +# endif +# endif +#elif defined(__FreeBSD__) || defined(__DragonFly__) +# include +# if (defined(__FreeBSD_version) && __FreeBSD_version >= 1200000) || \ + (defined(__DragonFly_version) && __DragonFly_version >= 500700) +# define HAVE_LINUX_COMPATIBLE_GETRANDOM +# endif +#endif + +#define UNUSED(x) (void)(x) + +typedef struct { + int random_data_source_fd; + int getrandom_available; +} MOBIRandom; + +#ifdef _WIN32 + +# include +# define RtlGenRandom SystemFunction036 +# if defined(__cplusplus) +extern "C" +# endif +BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +# ifdef _MSC_VER +# pragma comment(lib, "advapi32.lib") +# endif +#endif + +#if defined(__OpenBSD__) || defined(__CloudABI__) || defined(__wasi__) +# define HAVE_SAFE_ARC4RANDOM +#endif + +#ifdef HAVE_SAFE_ARC4RANDOM + +/** + @brief Read a buffer of random bytes using arc4random_buf call + + @param[in,out] handle Handle + @param[in,out] buf Buffer + @param[in] size Buffer size + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_randombytes_sysrandom_buf(MOBIRandom *handle, void *buf, const size_t size) { + UNUSED(handle); + arc4random_buf(buf, size); + return MOBI_SUCCESS; +} + +#else /* HAVE_SAFE_ARC4RANDOM */ + +# ifndef _WIN32 +/** + @brief Read a buffer of random bytes from file descriptoir + + @param[in] fd File descriptior + @param[in,out] buf_ Buffer + @param[in] size Buffer size + @return Number of bytes read + */ +static ssize_t mobi_safe_read(const int fd, void *buf_, size_t size) { + unsigned char *buf = (unsigned char *) buf_; + ssize_t readnb; + + do { + while ((readnb = read(fd, buf, size)) < (ssize_t) 0 && (errno == EINTR || errno == EAGAIN)); + if (readnb < (ssize_t) 0) { + return readnb; + } + if (readnb == (ssize_t) 0) { + break; + } + size -= (size_t) readnb; + buf += readnb; + } while (size > (ssize_t) 0); + + return (ssize_t) (buf - (unsigned char *) buf_); +} + +# ifdef BLOCK_ON_DEV_RANDOM +/** + @brief Block on /dev/random until enough entropy is available + + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_randombytes_block_on_dev_random(void) { + int fd = open("/dev/random", O_RDONLY); + if (fd == -1) { + return MOBI_SUCCESS; + } + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + int pret; + do { + pret = poll(&pfd, 1, -1); + } while (pret < 0 && (errno == EINTR || errno == EAGAIN)); + if (pret != 1) { + (void) close(fd); + errno = EIO; + return MOBI_DRM_RANDOM_ERR; + } + if (close(fd) != 0) { + return MOBI_DRM_RANDOM_ERR; + } + return MOBI_SUCCESS; +} +# endif /* BLOCK_ON_DEV_RANDOM */ + +/** + @brief Open random device, wait for enough entropy if supported + + @return Random device file descriptor + */ +static int mobi_randombytes_sysrandom_random_dev_open(void) { + +# ifdef BLOCK_ON_DEV_RANDOM + if (mobi_randombytes_block_on_dev_random() != MOBI_SUCCESS) { + return -1; + } +# endif + + static const char *devices[] = { + "/dev/urandom", + "/dev/random", NULL + }; + const char **device = devices; + + do { + int fd = open(*device, O_RDONLY); + if (fd != -1) { + struct stat st; + if (fstat(fd, &st) == 0 && +# ifdef S_ISNAM + (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) +# else + S_ISCHR(st.st_mode) +# endif + ) { +# if defined(F_SETFD) && defined(FD_CLOEXEC) + (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +# endif + return fd; + } + (void) close(fd); + } else if (errno == EINTR) { + continue; + } + device++; + } while (*device != NULL); + + errno = EIO; + return -1; +} + +# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM +/** + @brief Read a buffer of random bytes using getrandom system call + In libmobi we only need small KEYSIZE buffer, so we don't have to handle buffers over 256 bytes and read chunks + + @param[in,out] buf Buffer + @param[in] size Buffer size (up to 256 bytes) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_randombytes_linux_getrandom(void *buf, const size_t size) { + + if (size > 256U) { + debug_print("This function can only handle buffer size up to 256 bytes (%zu requested)\n", size); + return MOBI_PARAM_ERR; + } + int readnb; + do { + readnb = getrandom(buf, size, 0); + } while (readnb < 0 && (errno == EINTR || errno == EAGAIN)); + + if (readnb != (int) size) { + debug_print("Getrandom failed (%s)\n", strerror(errno)); + return MOBI_DRM_RANDOM_ERR; + } + return MOBI_SUCCESS; +} + +# endif /* HAVE_LINUX_COMPATIBLE_GETRANDOM */ + +/** + @brief Initialize random data source + + @param[in,out] handle Handle + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_randombytes_sysrandom_init(MOBIRandom *handle) { +# define NEEDS_INIT + const int errno_save = errno; + +# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM + { + unsigned char fodder[16]; + + if (mobi_randombytes_linux_getrandom(fodder, sizeof fodder) == MOBI_SUCCESS) { + handle->getrandom_available = 1; + errno = errno_save; + return MOBI_SUCCESS; + } + handle->getrandom_available = 0; + } +# endif + + if ((handle->random_data_source_fd = mobi_randombytes_sysrandom_random_dev_open()) == -1) { + debug_print("Couldn't open random device (%s)\n", strerror(errno)); + return MOBI_DRM_RANDOM_ERR; + } + errno = errno_save; + return MOBI_SUCCESS; +} + +/** + @brief Initialize random data source + + @param[in,out] handle Handle + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_randombytes_sysrandom_close(MOBIRandom *handle) { +# define NEEDS_CLOSE + MOBI_RET ret = MOBI_DRM_RANDOM_ERR; + if (handle->random_data_source_fd != -1 && close(handle->random_data_source_fd) == 0) { + handle->random_data_source_fd = -1; + ret = MOBI_SUCCESS; + } +# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM + if (handle->getrandom_available != 0) { + ret = MOBI_SUCCESS; + } +# endif + return ret; +} + +# endif /* _WIN32 */ + +/** + @brief Read a buffer of random bytes + + @param[in,out] handle Handle + @param[in,out] buf Buffer + @param[in] size Buffer size (up to 256 bytes) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_randombytes_sysrandom_buf(MOBIRandom *handle, void *buf, const size_t size) { +# ifndef _WIN32 +# ifdef HAVE_LINUX_COMPATIBLE_GETRANDOM + if (handle->getrandom_available != 0) { + return mobi_randombytes_linux_getrandom(buf, size); + } +# endif + if (handle->random_data_source_fd == -1 || + mobi_safe_read(handle->random_data_source_fd, buf, size) != (ssize_t) size) { + return MOBI_DRM_RANDOM_ERR; + } +# else /* _WIN32 */ + UNUSED(handle); + if (! RtlGenRandom((PVOID) buf, (ULONG) size)) { + return MOBI_DRM_RANDOM_ERR; + } +# endif /* _WIN32 */ + return MOBI_SUCCESS; +} + +#endif /* HAVE_SAFE_ARC4RANDOM */ + +/** + @brief Fill buffer with random bytes + + @param[in,out] buf Buffer + @param[in] size Buffer size (up to 256 bytes) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_randombytes(void *buf, const size_t size) { + + MOBIRandom handle = { + .random_data_source_fd = -1, + .getrandom_available = 0 + }; + + MOBI_RET ret; +#ifdef NEEDS_INIT + ret = mobi_randombytes_sysrandom_init(&handle); + if (ret != MOBI_SUCCESS) { + return ret; + } +#endif + + if (size > (size_t) 0U) { + ret = mobi_randombytes_sysrandom_buf(&handle, buf, size); + if (ret != MOBI_SUCCESS) { + debug_print("%s\n", "Generating random data failed"); + return ret; + } + } +#ifdef NEEDS_CLOSE + if (mobi_randombytes_sysrandom_close(&handle) != MOBI_SUCCESS) { + debug_print("%s\n", "Closing random data source failed"); + } +#endif + return MOBI_SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/randombytes.h b/Charcoal/Charcoal/libmobi-public/src/randombytes.h new file mode 100644 index 0000000..3a114f0 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/randombytes.h @@ -0,0 +1,25 @@ +/** @file randombytes.h + * + * Copyright (c) 2021 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_randombytes_h +#define libmobi_randombytes_h + +#include "mobi.h" + +/** + @brief Write n random bytes of high quality to buf + + @param[in,out] buf Buffer to be filled with random bytes + @param[in] len Buffer length + @return On success returns MOBI_SUCCESS + */ +MOBI_RET mobi_randombytes(void *buf, const size_t len); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/read.c b/Charcoal/Charcoal/libmobi-public/src/read.c new file mode 100644 index 0000000..baa78b3 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/read.c @@ -0,0 +1,924 @@ +/** @file read.c + * @brief Functions for reading and parsing of MOBI document + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + + +#include +#include +#include +#include "read.h" +#include "util.h" +#include "index.h" +#include "debug.h" + +/** + @brief Read palm database header from file into MOBIData structure (MOBIPdbHeader) + + @param[in,out] m MOBIData structure to be filled with read data + @param[in] file Filedescriptor to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_load_pdbheader(MOBIData *m, FILE *file) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (!file) { + return MOBI_FILE_NOT_FOUND; + } + MOBIBuffer *buf = mobi_buffer_init(PALMDB_HEADER_LEN); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + const size_t len = fread(buf->data, 1, PALMDB_HEADER_LEN, file); + if (len != PALMDB_HEADER_LEN) { + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + m->ph = calloc(1, sizeof(MOBIPdbHeader)); + if (m->ph == NULL) { + debug_print("%s", "Memory allocation for pdb header failed\n"); + mobi_buffer_free(buf); + return MOBI_MALLOC_FAILED; + } + /* parse header */ + mobi_buffer_getstring(m->ph->name, buf, PALMDB_NAME_SIZE_MAX); + m->ph->attributes = mobi_buffer_get16(buf); + m->ph->version = mobi_buffer_get16(buf); + m->ph->ctime = mobi_buffer_get32(buf); + m->ph->mtime = mobi_buffer_get32(buf); + m->ph->btime = mobi_buffer_get32(buf); + m->ph->mod_num = mobi_buffer_get32(buf); + m->ph->appinfo_offset = mobi_buffer_get32(buf); + m->ph->sortinfo_offset = mobi_buffer_get32(buf); + mobi_buffer_getstring(m->ph->type, buf, 4); + mobi_buffer_getstring(m->ph->creator, buf, 4); + m->ph->uid = mobi_buffer_get32(buf); + m->ph->next_rec = mobi_buffer_get32(buf); + m->ph->rec_count = mobi_buffer_get16(buf); + mobi_buffer_free(buf); + return MOBI_SUCCESS; +} + +/** + @brief Read list of database records from file into MOBIData structure (MOBIPdbRecord) + + @param[in,out] m MOBIData structure to be filled with read data + @param[in] file Filedescriptor to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_load_reclist(MOBIData *m, FILE *file) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (!file) { + debug_print("%s", "File not ready\n"); + return MOBI_FILE_NOT_FOUND; + } + m->rec = calloc(1, sizeof(MOBIPdbRecord)); + if (m->rec == NULL) { + debug_print("%s", "Memory allocation for pdb record failed\n"); + return MOBI_MALLOC_FAILED; + } + MOBIPdbRecord *curr = m->rec; + for (int i = 0; i < m->ph->rec_count; i++) { + MOBIBuffer *buf = mobi_buffer_init(PALMDB_RECORD_INFO_SIZE); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + const size_t len = fread(buf->data, 1, PALMDB_RECORD_INFO_SIZE, file); + if (len != PALMDB_RECORD_INFO_SIZE) { + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + if (i > 0) { + curr->next = calloc(1, sizeof(MOBIPdbRecord)); + if (curr->next == NULL) { + debug_print("%s", "Memory allocation for pdb record failed\n"); + mobi_buffer_free(buf); + return MOBI_MALLOC_FAILED; + } + curr = curr->next; + } + curr->offset = mobi_buffer_get32(buf); + curr->attributes = mobi_buffer_get8(buf); + const uint8_t h = mobi_buffer_get8(buf); + const uint16_t l = mobi_buffer_get16(buf); + curr->uid = (uint32_t) h << 16 | l; + curr->next = NULL; + mobi_buffer_free(buf); + } + return MOBI_SUCCESS; +} + +/** + @brief Read record data and size from file into MOBIData structure (MOBIPdbRecord) + + @param[in,out] m MOBIData structure to be filled with read data + @param[in] file Filedescriptor to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_load_rec(MOBIData *m, FILE *file) { + MOBI_RET ret; + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + MOBIPdbRecord *curr = m->rec; + while (curr != NULL) { + MOBIPdbRecord *next; + size_t size; + if (curr->next != NULL) { + next = curr->next; + size = next->offset - curr->offset; + } else { + fseek(file, 0, SEEK_END); + long diff = ftell(file) - curr->offset; + if (diff <= 0) { + debug_print("Wrong record size: %li\n", diff); + return MOBI_DATA_CORRUPT; + } + size = (size_t) diff; + next = NULL; + } + + curr->size = size; + ret = mobi_load_recdata(curr, file); + if (ret != MOBI_SUCCESS) { + debug_print("Error loading record uid %i data\n", curr->uid); + mobi_free_rec(m); + return ret; + } + curr = next; + } + return MOBI_SUCCESS; +} + +/** + @brief Read record data from file into MOBIPdbRecord structure + + @param[in,out] rec MOBIPdbRecord structure to be filled with read data + @param[in] file Filedescriptor to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_load_recdata(MOBIPdbRecord *rec, FILE *file) { + const int ret = fseek(file, rec->offset, SEEK_SET); + if (ret != 0) { + debug_print("Record %i not found\n", rec->uid); + return MOBI_DATA_CORRUPT; + } + rec->data = malloc(rec->size); + if (rec->data == NULL) { + debug_print("%s", "Memory allocation for pdb record data failed\n"); + return MOBI_MALLOC_FAILED; + } + const size_t len = fread(rec->data, 1, rec->size, file); + if (len < rec->size) { + debug_print("Truncated data in record %i\n", rec->uid); + return MOBI_DATA_CORRUPT; + } + return MOBI_SUCCESS; +} + +/** + @brief Parse EXTH header from Record 0 into MOBIData structure (MOBIExthHeader) + + @param[in,out] m MOBIData structure to be filled with parsed data + @param[in] buf MOBIBuffer buffer to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_extheader(MOBIData *m, MOBIBuffer *buf) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + char exth_magic[5]; + const size_t header_length = 12; + mobi_buffer_getstring(exth_magic, buf, 4); + const size_t exth_length = mobi_buffer_get32(buf) - header_length; + const size_t rec_count = mobi_buffer_get32(buf); + if (strncmp(exth_magic, EXTH_MAGIC, 4) != 0 || + exth_length + buf->offset > buf->maxlen || + rec_count == 0 || rec_count > MOBI_EXTH_MAXCNT) { + debug_print("%s", "Sanity checks for EXTH header failed\n"); + return MOBI_DATA_CORRUPT; + } + const size_t saved_maxlen = buf->maxlen; + buf->maxlen = exth_length + buf->offset; + m->eh = calloc(1, sizeof(MOBIExthHeader)); + if (m->eh == NULL) { + debug_print("%s", "Memory allocation for EXTH header failed\n"); + return MOBI_MALLOC_FAILED; + } + MOBIExthHeader *curr = m->eh; + for (size_t i = 0; i < rec_count; i++) { + if (curr->data) { + curr->next = calloc(1, sizeof(MOBIExthHeader)); + if (curr->next == NULL) { + debug_print("%s", "Memory allocation for EXTH header failed\n"); + mobi_free_eh(m); + return MOBI_MALLOC_FAILED; + } + curr = curr->next; + } + curr->tag = mobi_buffer_get32(buf); + /* data size = record size minus 8 bytes for uid and size */ + curr->size = mobi_buffer_get32(buf) - 8; + if (curr->size == 0) { + debug_print("Skip record %i, data too short\n", curr->tag); + continue; + } + if (buf->offset + curr->size > buf->maxlen) { + debug_print("Record %i too long\n", curr->tag); + mobi_free_eh(m); + return MOBI_DATA_CORRUPT; + } + curr->data = malloc(curr->size); + if (curr->data == NULL) { + debug_print("Memory allocation for EXTH record %i failed\n", curr->tag); + mobi_free_eh(m); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_getraw(curr->data, buf, curr->size); + curr->next = NULL; + } + buf->maxlen = saved_maxlen; + return MOBI_SUCCESS; +} + +/** + @brief Parse MOBI header from Record 0 into MOBIData structure (MOBIMobiHeader) + + @param[in,out] m MOBIData structure to be filled with parsed data + @param[in] buf MOBIBuffer buffer to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_mobiheader(MOBIData *m, MOBIBuffer *buf) { + int isKF8 = 0; + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + m->mh = calloc(1, sizeof(MOBIMobiHeader)); + if (m->mh == NULL) { + debug_print("%s", "Memory allocation for MOBI header failed\n"); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_getstring(m->mh->mobi_magic, buf, 4); + mobi_buffer_dup32(&m->mh->header_length, buf); + if (strcmp(m->mh->mobi_magic, MOBI_MAGIC) != 0 || m->mh->header_length == NULL) { + debug_print("%s", "MOBI header not found\n"); + mobi_free_mh(m->mh); + m->mh = NULL; + return MOBI_DATA_CORRUPT; + } + const size_t saved_maxlen = buf->maxlen; + /* some old files declare zero length mobi header, try to read first 24 bytes anyway */ + uint32_t header_length = (*m->mh->header_length > 0) ? *m->mh->header_length : 24; + /* read only declared MOBI header length (curr offset minus 8 already read bytes) */ + const size_t left_length = header_length + buf->offset - 8; + buf->maxlen = saved_maxlen < left_length ? saved_maxlen : left_length; + mobi_buffer_dup32(&m->mh->mobi_type, buf); + uint32_t encoding = mobi_buffer_get32(buf); + if (encoding == 1252) { + m->mh->text_encoding = malloc(sizeof(MOBIEncoding)); + if (m->mh->text_encoding == NULL) { + debug_print("%s", "Memory allocation for MOBI header failed\n"); + return MOBI_MALLOC_FAILED; + } + *m->mh->text_encoding = MOBI_CP1252; + } + else if (encoding == 65001) { + m->mh->text_encoding = malloc(sizeof(MOBIEncoding)); + if (m->mh->text_encoding == NULL) { + debug_print("%s", "Memory allocation for MOBI header failed\n"); + return MOBI_MALLOC_FAILED; + } + *m->mh->text_encoding = MOBI_UTF8; + } else { + debug_print("Unknown encoding in mobi header: %i\n", encoding); + } + mobi_buffer_dup32(&m->mh->uid, buf); + mobi_buffer_dup32(&m->mh->version, buf); + if (header_length >= MOBI_HEADER_V7_SIZE + && m->mh->version && *m->mh->version == 8) { + isKF8 = 1; + } + mobi_buffer_dup32(&m->mh->orth_index, buf); + mobi_buffer_dup32(&m->mh->infl_index, buf); + mobi_buffer_dup32(&m->mh->names_index, buf); + mobi_buffer_dup32(&m->mh->keys_index, buf); + mobi_buffer_dup32(&m->mh->extra0_index, buf); + mobi_buffer_dup32(&m->mh->extra1_index, buf); + mobi_buffer_dup32(&m->mh->extra2_index, buf); + mobi_buffer_dup32(&m->mh->extra3_index, buf); + mobi_buffer_dup32(&m->mh->extra4_index, buf); + mobi_buffer_dup32(&m->mh->extra5_index, buf); + mobi_buffer_dup32(&m->mh->non_text_index, buf); + mobi_buffer_dup32(&m->mh->full_name_offset, buf); + mobi_buffer_dup32(&m->mh->full_name_length, buf); + mobi_buffer_dup32(&m->mh->locale, buf); + mobi_buffer_dup32(&m->mh->dict_input_lang, buf); + mobi_buffer_dup32(&m->mh->dict_output_lang, buf); + mobi_buffer_dup32(&m->mh->min_version, buf); + mobi_buffer_dup32(&m->mh->image_index, buf); + mobi_buffer_dup32(&m->mh->huff_rec_index, buf); + mobi_buffer_dup32(&m->mh->huff_rec_count, buf); + mobi_buffer_dup32(&m->mh->datp_rec_index, buf); + mobi_buffer_dup32(&m->mh->datp_rec_count, buf); + mobi_buffer_dup32(&m->mh->exth_flags, buf); + mobi_buffer_seek(buf, 32); /* 32 unknown bytes */ + mobi_buffer_dup32(&m->mh->unknown6, buf); + mobi_buffer_dup32(&m->mh->drm_offset, buf); + mobi_buffer_dup32(&m->mh->drm_count, buf); + mobi_buffer_dup32(&m->mh->drm_size, buf); + mobi_buffer_dup32(&m->mh->drm_flags, buf); + mobi_buffer_seek(buf, 8); /* 8 unknown bytes */ + if (isKF8) { + mobi_buffer_dup32(&m->mh->fdst_index, buf); + } else { + mobi_buffer_dup16(&m->mh->first_text_index, buf); + mobi_buffer_dup16(&m->mh->last_text_index, buf); + } + mobi_buffer_dup32(&m->mh->fdst_section_count, buf); + mobi_buffer_dup32(&m->mh->fcis_index, buf); + mobi_buffer_dup32(&m->mh->fcis_count, buf); + mobi_buffer_dup32(&m->mh->flis_index, buf); + mobi_buffer_dup32(&m->mh->flis_count, buf); + mobi_buffer_dup32(&m->mh->unknown10, buf); + mobi_buffer_dup32(&m->mh->unknown11, buf); + mobi_buffer_dup32(&m->mh->srcs_index, buf); + mobi_buffer_dup32(&m->mh->srcs_count, buf); + mobi_buffer_dup32(&m->mh->unknown12, buf); + mobi_buffer_dup32(&m->mh->unknown13, buf); + mobi_buffer_seek(buf, 2); /* 2 byte fill */ + mobi_buffer_dup16(&m->mh->extra_flags, buf); + mobi_buffer_dup32(&m->mh->ncx_index, buf); + if (isKF8) { + mobi_buffer_dup32(&m->mh->fragment_index, buf); + mobi_buffer_dup32(&m->mh->skeleton_index, buf); + } else { + mobi_buffer_dup32(&m->mh->unknown14, buf); + mobi_buffer_dup32(&m->mh->unknown15, buf); + } + mobi_buffer_dup32(&m->mh->datp_index, buf); + if (isKF8) { + mobi_buffer_dup32(&m->mh->guide_index, buf); + } else { + mobi_buffer_dup32(&m->mh->unknown16, buf); + } + mobi_buffer_dup32(&m->mh->unknown17, buf); + mobi_buffer_dup32(&m->mh->unknown18, buf); + mobi_buffer_dup32(&m->mh->unknown19, buf); + mobi_buffer_dup32(&m->mh->unknown20, buf); + if (buf->maxlen > buf->offset) { + debug_print("Skipping %zu unknown bytes in MOBI header\n", (buf->maxlen - buf->offset)); + mobi_buffer_setpos(buf, buf->maxlen); + } + buf->maxlen = saved_maxlen; + /* get full name stored at m->mh->full_name_offset */ + if (m->mh->full_name_offset && m->mh->full_name_length) { + const size_t saved_offset = buf->offset; + const uint32_t full_name_length = min(*m->mh->full_name_length, MOBI_TITLE_SIZEMAX); + mobi_buffer_setpos(buf, *m->mh->full_name_offset); + m->mh->full_name = malloc(full_name_length + 1); + if (m->mh->full_name == NULL) { + debug_print("%s", "Memory allocation for full name failed\n"); + return MOBI_MALLOC_FAILED; + } + if (full_name_length) { + mobi_buffer_getstring(m->mh->full_name, buf, full_name_length); + } else { + m->mh->full_name[0] = '\0'; + } + mobi_buffer_setpos(buf, saved_offset); + } + return MOBI_SUCCESS; +} + +/** + @brief Parse Record 0 into MOBIData structure + + This function will parse MOBIRecord0Header, MOBIMobiHeader and MOBIExthHeader + + @param[in,out] m MOBIData structure to be filled with parsed data + @param[in] seqnumber Sequential number of the palm database record + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_record0(MOBIData *m, const size_t seqnumber) { + MOBI_RET ret; + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + const MOBIPdbRecord *record0 = mobi_get_record_by_seqnumber(m, seqnumber); + if (record0 == NULL) { + debug_print("%s", "Record 0 not loaded\n"); + return MOBI_DATA_CORRUPT; + } + if (record0->size < RECORD0_HEADER_LEN) { + debug_print("%s", "Record 0 too short\n"); + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init_null(record0->data, record0->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + m->rh = calloc(1, sizeof(MOBIRecord0Header)); + if (m->rh == NULL) { + debug_print("%s", "Memory allocation for record 0 header failed\n"); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + /* parse palmdoc header */ + const uint16_t compression = mobi_buffer_get16(buf); + mobi_buffer_seek(buf, 2); // unused 2 bytes, zeroes + if ((compression != MOBI_COMPRESSION_NONE && + compression != MOBI_COMPRESSION_PALMDOC && + compression != MOBI_COMPRESSION_HUFFCDIC)) { + debug_print("Wrong record0 header: %c%c%c%c\n", record0->data[0], record0->data[1], record0->data[2], record0->data[3]); + mobi_buffer_free_null(buf); + free(m->rh); + m->rh = NULL; + return MOBI_DATA_CORRUPT; + } + m->rh->compression_type = compression; + m->rh->text_length = mobi_buffer_get32(buf); + m->rh->text_record_count = mobi_buffer_get16(buf); + m->rh->text_record_size = mobi_buffer_get16(buf); + m->rh->encryption_type = mobi_buffer_get16(buf); + m->rh->unknown1 = mobi_buffer_get16(buf); + if (mobi_is_mobipocket(m)) { + /* parse mobi header if present */ + ret = mobi_parse_mobiheader(m, buf); + if (ret == MOBI_SUCCESS) { + /* parse exth header if present */ + mobi_parse_extheader(m, buf); + } + } + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Calculate the size of extra bytes at the end of text record + + @param[in] record MOBIPdbRecord structure containing the record + @param[in] flags Flags from MOBI header (extra_flags) + @return The size of trailing bytes, MOBI_NOTSET on failure + */ +size_t mobi_get_record_extrasize(const MOBIPdbRecord *record, const uint16_t flags) { + size_t extra_size = 0; + MOBIBuffer *buf = mobi_buffer_init_null(record->data, record->size); + if (buf == NULL) { + debug_print("%s", "Buffer init in extrasize failed\n"); + return MOBI_NOTSET; + } + /* set pointer at the end of the record data */ + mobi_buffer_setpos(buf, buf->maxlen - 1); + for (int bit = 15; bit > 0; bit--) { + if (flags & (1 << bit)) { + /* bit is set */ + size_t len = 0; + /* size contains varlen itself and optional data */ + const uint32_t size = mobi_buffer_get_varlen_dec(buf, &len); + /* skip data */ + /* TODO: read and store in record struct */ + mobi_buffer_seek(buf, - (int)(size - len)); + extra_size += size; + } + } + /* check bit 0 */ + if (flags & 1) { + const uint8_t b = mobi_buffer_get8(buf); + /* two first bits hold size */ + extra_size += (b & 0x3) + 1; + } + mobi_buffer_free_null(buf); + return extra_size; +} + +/** + @brief Calculate the size of extra multibyte section at the end of text record + + @param[in] record MOBIPdbRecord structure containing the record + @param[in] flags Flags from MOBI header (extra_flags) + @return The size of trailing bytes, MOBI_NOTSET on failure + */ +size_t mobi_get_record_mb_extrasize(const MOBIPdbRecord *record, const uint16_t flags) { + size_t extra_size = 0; + if (flags & 1) { + MOBIBuffer *buf = mobi_buffer_init_null(record->data, record->size); + if (buf == NULL) { + debug_print("%s", "Buffer init in extrasize failed\n"); + return MOBI_NOTSET; + } + /* set pointer at the end of the record data */ + mobi_buffer_setpos(buf, buf->maxlen - 1); + for (int bit = 15; bit > 0; bit--) { + if (flags & (1 << bit)) { + /* bit is set */ + size_t len = 0; + /* size contains varlen itself and optional data */ + const uint32_t size = mobi_buffer_get_varlen_dec(buf, &len); + /* skip data */ + /* TODO: read and store in record struct */ + mobi_buffer_seek(buf, - (int)(size - len)); + } + } + /* read multibyte section */ + const uint8_t b = mobi_buffer_get8(buf); + /* two first bits hold size */ + extra_size += (b & 0x3) + 1; + mobi_buffer_free_null(buf); + } + return extra_size; +} + +/** + @brief Parse HUFF record into MOBIHuffCdic structure + + @param[in,out] huffcdic MOBIHuffCdic structure to be filled with parsed data + @param[in] record MOBIPdbRecord structure containing the record + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_huff(MOBIHuffCdic *huffcdic, const MOBIPdbRecord *record) { + MOBIBuffer *buf = mobi_buffer_init_null(record->data, record->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char huff_magic[5]; + mobi_buffer_getstring(huff_magic, buf, 4); + const size_t header_length = mobi_buffer_get32(buf); + if (strncmp(huff_magic, HUFF_MAGIC, 4) != 0 || header_length < HUFF_HEADER_LEN) { + debug_print("HUFF wrong magic: %s\n", huff_magic); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + const size_t data1_offset = mobi_buffer_get32(buf); + const size_t data2_offset = mobi_buffer_get32(buf); + /* skip little-endian table offsets */ + mobi_buffer_setpos(buf, data1_offset); + if (buf->offset + (256 * 4) > buf->maxlen) { + debug_print("%s", "HUFF data1 too short\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* read 256 indices from data1 big-endian */ + for (int i = 0; i < 256; i++) { + huffcdic->table1[i] = mobi_buffer_get32(buf); + } + mobi_buffer_setpos(buf, data2_offset); + if (buf->offset + (64 * 4) > buf->maxlen) { + debug_print("%s", "HUFF data2 too short\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* read 32 mincode-maxcode pairs from data2 big-endian */ + huffcdic->mincode_table[0] = 0; + huffcdic->maxcode_table[0] = 0xFFFFFFFF; + for (int i = 1; i < HUFF_CODETABLE_SIZE; i++) { + const uint32_t mincode = mobi_buffer_get32(buf); + const uint32_t maxcode = mobi_buffer_get32(buf); + huffcdic->mincode_table[i] = mincode << (32 - i); + huffcdic->maxcode_table[i] = ((maxcode + 1) << (32 - i)) - 1; + } + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Parse CDIC record into MOBIHuffCdic structure + + @param[in,out] huffcdic MOBIHuffCdic structure to be filled with parsed data + @param[in] record MOBIPdbRecord structure containing the record + @param[in] num Number of CDIC record in a set, starting from zero + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_cdic(MOBIHuffCdic *huffcdic, const MOBIPdbRecord *record, const size_t num) { + MOBIBuffer *buf = mobi_buffer_init_null(record->data, record->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char cdic_magic[5]; + mobi_buffer_getstring(cdic_magic, buf, 4); + const size_t header_length = mobi_buffer_get32(buf); + if (strncmp(cdic_magic, CDIC_MAGIC, 4) != 0 || header_length < CDIC_HEADER_LEN) { + debug_print("CDIC wrong magic: %s or declared header length: %zu\n", cdic_magic, header_length); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* variables in huffcdic initialized to zero with calloc */ + /* save initial count and length */ + size_t index_count = mobi_buffer_get32(buf); + const size_t code_length = mobi_buffer_get32(buf); + if (huffcdic->code_length && huffcdic->code_length != code_length) { + debug_print("CDIC different code length %zu in record %i, previous was %zu\n", huffcdic->code_length, record->uid, code_length); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + if (huffcdic->index_count && huffcdic->index_count != index_count) { + debug_print("CDIC different index count %zu in record %i, previous was %zu\n", huffcdic->index_count, record->uid, index_count); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + if (code_length == 0 || code_length > HUFF_CODELEN_MAX) { + debug_print("Code length exceeds sanity checks (%zu)\n", code_length); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + huffcdic->code_length = code_length; + huffcdic->index_count = index_count; + if (index_count == 0) { + debug_print("%s", "CDIC index count is null"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* allocate memory for symbol offsets if not already allocated */ + if (num == 0) { + if (index_count > (1 << HUFF_CODELEN_MAX) * CDIC_RECORD_MAXCNT) { + debug_print("CDIC index count too large %zu\n", index_count); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + huffcdic->symbol_offsets = malloc(index_count * sizeof(*huffcdic->symbol_offsets)); + if (huffcdic->symbol_offsets == NULL) { + debug_print("%s", "CDIC cannot allocate memory"); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + } + index_count -= huffcdic->index_read; + /* limit number of records read to code_length bits */ + if (index_count >> code_length) { + index_count = (1 << code_length); + } + if (buf->offset + (index_count * 2) > buf->maxlen) { + debug_print("%s", "CDIC indices data too short\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* read i * 2 byte big-endian indices */ + while (index_count--) { + const uint16_t offset = mobi_buffer_get16(buf); + const size_t saved_pos = buf->offset; + mobi_buffer_setpos(buf, offset + CDIC_HEADER_LEN); + const size_t len = mobi_buffer_get16(buf) & 0x7fff; + if (buf->error != MOBI_SUCCESS || buf->offset + len > buf->maxlen) { + debug_print("%s", "CDIC offset beyond buffer\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_setpos(buf, saved_pos); + huffcdic->symbol_offsets[huffcdic->index_read++] = offset; + } + if (buf->offset + code_length > buf->maxlen) { + debug_print("%s", "CDIC dictionary data too short\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + /* copy pointer to data */ + huffcdic->symbols[num] = record->data + CDIC_HEADER_LEN; + /* free buffer */ + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Parse a set of HUFF and CDIC records into MOBIHuffCdic structure + + @param[in] m MOBIData structure with loaded MOBI document + @param[in,out] huffcdic MOBIHuffCdic structure to be filled with parsed data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_huffdic(const MOBIData *m, MOBIHuffCdic *huffcdic) { + MOBI_RET ret; + const size_t offset = mobi_get_kf8offset(m); + if (m->mh == NULL || m->mh->huff_rec_index == NULL || m->mh->huff_rec_count == NULL) { + debug_print("%s", "HUFF/CDIC records metadata not found in MOBI header\n"); + return MOBI_DATA_CORRUPT; + } + const size_t huff_rec_index = *m->mh->huff_rec_index + offset; + const size_t huff_rec_count = *m->mh->huff_rec_count; + if (huff_rec_count > HUFF_RECORD_MAXCNT) { + debug_print("Too many HUFF record (%zu)\n", huff_rec_count); + return MOBI_DATA_CORRUPT; + } + const MOBIPdbRecord *curr = mobi_get_record_by_seqnumber(m, huff_rec_index); + if (curr == NULL || huff_rec_count < 2) { + debug_print("%s", "HUFF/CDIC record not found\n"); + return MOBI_DATA_CORRUPT; + } + if (curr->size < HUFF_RECORD_MINSIZE) { + debug_print("HUFF record too short (%zu b)\n", curr->size); + return MOBI_DATA_CORRUPT; + } + ret = mobi_parse_huff(huffcdic, curr); + if (ret != MOBI_SUCCESS) { + debug_print("%s", "HUFF parsing failed\n"); + return ret; + } + curr = curr->next; + /* allocate memory for symbols data in each CDIC record */ + huffcdic->symbols = malloc((huff_rec_count - 1) * sizeof(*huffcdic->symbols)); + if (huffcdic->symbols == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + /* get following CDIC records */ + size_t i = 0; + while (i < huff_rec_count - 1) { + if (curr == NULL) { + debug_print("%s\n", "CDIC record not found"); + return MOBI_DATA_CORRUPT; + } + ret = mobi_parse_cdic(huffcdic, curr, i++); + if (ret != MOBI_SUCCESS) { + debug_print("%s", "CDIC parsing failed\n"); + return ret; + } + curr = curr->next; + } + if (huffcdic->index_count != huffcdic->index_read) { + debug_print("CDIC: wrong read index count: %zu, total: %zu\n", huffcdic->index_read, huffcdic->index_count); + return MOBI_DATA_CORRUPT; + } + return MOBI_SUCCESS; +} + +/** + @brief Parse FDST record into MOBIRawml structure (MOBIFdst member) + + @param[in] m MOBIData structure with loaded MOBI document + @param[in,out] rawml MOBIRawml structure to be filled with parsed data + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_fdst(const MOBIData *m, MOBIRawml *rawml) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + const size_t fdst_record_number = mobi_get_fdst_record_number(m); + if (fdst_record_number == MOBI_NOTSET) { + return MOBI_DATA_CORRUPT; + } + const MOBIPdbRecord *fdst_record = mobi_get_record_by_seqnumber(m, fdst_record_number); + if (fdst_record == NULL) { + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init_null(fdst_record->data, fdst_record->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char fdst_magic[5]; + mobi_buffer_getstring(fdst_magic, buf, 4); + const size_t data_offset = mobi_buffer_get32(buf); + const size_t section_count = mobi_buffer_get32(buf); + if (strncmp(fdst_magic, FDST_MAGIC, 4) != 0 || + section_count <= 1 || + section_count != *m->mh->fdst_section_count || + data_offset != 12) { + debug_print("FDST wrong magic: %s, sections count: %zu or data offset: %zu\n", fdst_magic, section_count, data_offset); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + if ((buf->maxlen - buf->offset) < section_count * 8) { + debug_print("%s", "Record FDST too short\n"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + rawml->fdst = malloc(sizeof(MOBIFdst)); + if (rawml->fdst == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_buffer_free_null(buf); + return MOBI_MALLOC_FAILED; + } + rawml->fdst->fdst_section_count = section_count; + rawml->fdst->fdst_section_starts = malloc(sizeof(*rawml->fdst->fdst_section_starts) * section_count); + if (rawml->fdst->fdst_section_starts == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_buffer_free_null(buf); + free(rawml->fdst); + rawml->fdst = NULL; + return MOBI_MALLOC_FAILED; + } + rawml->fdst->fdst_section_ends = malloc(sizeof(*rawml->fdst->fdst_section_ends) * section_count); + if (rawml->fdst->fdst_section_ends == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_buffer_free_null(buf); + free(rawml->fdst->fdst_section_starts); + free(rawml->fdst); + rawml->fdst = NULL; + return MOBI_MALLOC_FAILED; + } + size_t i = 0; + while (i < section_count) { + rawml->fdst->fdst_section_starts[i] = mobi_buffer_get32(buf); + rawml->fdst->fdst_section_ends[i] = mobi_buffer_get32(buf); + debug_print("FDST[%zu]:\t%i\t%i\n", i, rawml->fdst->fdst_section_starts[i], rawml->fdst->fdst_section_ends[i]); + i++; + } + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Read MOBI document from file into MOBIData structure + + @param[in,out] m MOBIData structure to be filled with read data + @param[in] file File descriptor to read from + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_load_file(MOBIData *m, FILE *file) { + MOBI_RET ret; + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + ret = mobi_load_pdbheader(m, file); + if (ret != MOBI_SUCCESS) { + return ret; + } + if (strcmp(m->ph->type, "BOOK") != 0 && strcmp(m->ph->type, "TEXt") != 0) { + debug_print("Unsupported file type: %s\n", m->ph->type); + return MOBI_FILE_UNSUPPORTED; + } + if (m->ph->rec_count == 0) { + debug_print("%s", "No records found\n"); + return MOBI_DATA_CORRUPT; + } + ret = mobi_load_reclist(m, file); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_load_rec(m, file); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_parse_record0(m, 0); + if (ret != MOBI_SUCCESS) { + return ret; + } + if (m->rh && m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + /* try to set key for encryption type 1 */ + debug_print("Trying to set key for encryption type 1%s", "\n"); + mobi_drm_setkey(m, NULL); + } + /* if EXTH is loaded parse KF8 record0 for hybrid KF7/KF8 file */ + if (m->eh) { + const size_t boundary_rec_number = mobi_get_kf8boundary_seqnumber(m); + if (boundary_rec_number != MOBI_NOTSET && boundary_rec_number < UINT32_MAX) { + /* it is a hybrid KF7/KF8 file */ + m->kf8_boundary_offset = (uint32_t) boundary_rec_number; + m->next = mobi_init(); + /* link pdb header and records data to KF8data structure */ + m->next->ph = m->ph; + m->next->rec = m->rec; + m->next->drm_key = m->drm_key; + m->next->internals = m->internals; + /* close next loop */ + m->next->next = m; + ret = mobi_parse_record0(m->next, boundary_rec_number + 1); + if (ret != MOBI_SUCCESS) { + return ret; + } + /* swap to kf8 part if use_kf8 flag is set */ + if (m->use_kf8) { + mobi_swap_mobidata(m); + } + } + } + return MOBI_SUCCESS; +} + +/** + @brief Read MOBI document from a path into MOBIData structure + + @param[in,out] m MOBIData structure to be filled with read data + @param[in] path Path to a MOBI document on disk (eg. /home/me/test.mobi) + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_load_filename(MOBIData *m, const char *path) { + FILE *file = fopen(path, "rb"); + if (file == NULL) { + debug_print("%s", "File not found\n"); + return MOBI_FILE_NOT_FOUND; + } + const MOBI_RET ret = mobi_load_file(m, file); + fclose(file); + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/read.h b/Charcoal/Charcoal/libmobi-public/src/read.h new file mode 100644 index 0000000..cbeff71 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/read.h @@ -0,0 +1,28 @@ +/** @file read.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_read_h +#define libmobi_read_h + +#include "config.h" +#include "mobi.h" +#include "memory.h" +#include "compression.h" + +#define MOBI_EXTH_MAXCNT 1024 + +MOBI_RET mobi_parse_fdst(const MOBIData *m, MOBIRawml *rawml); +MOBI_RET mobi_parse_huffdic(const MOBIData *m, MOBIHuffCdic *cdic); +MOBI_RET mobi_load_pdbheader(MOBIData *m, FILE *file); +MOBI_RET mobi_load_reclist(MOBIData *m, FILE *file); +MOBI_RET mobi_load_rec(MOBIData *m, FILE *file); +MOBI_RET mobi_load_recdata(MOBIPdbRecord *rec, FILE *file); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/sha1.c b/Charcoal/Charcoal/libmobi-public/src/sha1.c new file mode 100644 index 0000000..3c7f873 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/sha1.c @@ -0,0 +1,281 @@ +/* + SHA-1 in C + By Steve Reid + 100% Public Domain + ----------------- + Modified 7/98 + By James H. Brown + Still 100% Public Domain + Corrected a problem which generated improper hash values on 16 bit machines + Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int + len) + to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned + long len) + The 'len' parameter was declared an int which works fine on 32 bit machines. + However, on 16 bit machines an int is too small for the shifts being done + against + it. This caused the hash function to generate incorrect values if len was + greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + Since the file IO in main() reads 16K at a time, any file 8K or larger would + be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million + "a"s). + I also changed the declaration of variables i & j in SHA1Update to + unsigned long from unsigned int for the same reason. + These changes should make no difference to any 32 bit implementations since + an + int and a long are the same size in those environments. + -- + I also corrected a few compiler warnings generated by Borland C. + 1. Added #include for exit() prototype + 2. Removed unused variable 'j' in SHA1Final + 3. Changed exit(0) to return(0) at end of main. + ALL changes I made can be located by searching for comments containing 'JHB' + ----------------- + Modified 8/98 + By Steve Reid + Still 100% public domain + 1- Removed #include and used return() instead of exit() + 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) + 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + ----------------- + Modified 4/01 + By Saul Kravitz + Still 100% PD + Modified to run on Compaq Alpha hardware. + ----------------- + Modified 07/2002 + By Ralph Giles + Still 100% public domain + modified for use with stdint types, autoconf + code cleanup, removed attribution comments + switched SHA1Final() argument order for consistency + use SHA1_ prefix for public api + move public api to sha1.h + */ + +/* + Test Vectors (from FIPS PUB 180-1) + "abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F + */ + +/* #define SHA1HANDSOFF */ + +#include +#include +#include + +#include "sha1.h" +#define UNUSED(x) (void)(x) + +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#define blk0(i) (block->l[i] = (((uint32_t)block->c[i*4 ] << 24) | \ + ((uint32_t)block->c[i*4 + 1] << 16) | \ + ((uint32_t)block->c[i*4 + 2] << 8) | \ + ((uint32_t)block->c[i*4 + 3] ))) +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ +^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg) { + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif /* VERBOSE */ + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) { + uint32_t a, b, c, d, e; + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + +#ifdef SHA1HANDSOFF + static uint8_t workspace[64]; + block = (CHAR64LONG16*) workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*) buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; + UNUSED(a);UNUSED(b);UNUSED(c);UNUSED(d);UNUSED(e); +} + + +/* SHA1Init - Initialize new context */ +void SHA1_Init(SHA1_CTX* context) { + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ +void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len) { + size_t i, j; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); + +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ +void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]) { + uint32_t i; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1_Update(context, (uint8_t *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (uint8_t *)"\0", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = (uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + + /* Wipe variables */ + i = 0; + UNUSED(i); + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); /* SWR */ + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} + +/*************************************************************/ + +#ifdef TEST +int main(int argc, char** argv) { + int i, j; + SHA1_CTX context; + unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384]; + FILE* file; + if (argc > 2) { + puts("Public domain SHA-1 implementation - by Steve Reid "); + puts("Modified for 16 bit environments 7/98 - by James H. Brown "); /* JHB */ + puts("Produces the SHA-1 hash of a file, or stdin if no file is specified."); + return(0); + } + if (argc < 2) { + file = stdin; + } + else { + if (!(file = fopen(argv[1], "rb"))) { + fputs("Unable to open file.", stderr); + return(-1); + } + } + SHA1_Init(&context); + while (!feof(file)) { /* note: what if ferror(file) */ + i = fread(buffer, 1, 16384, file); + SHA1_Update(&context, buffer, i); + } + SHA1_Final(&context, digest); + fclose(file); + for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) { + for (j = 0; j < 4; j++) { + printf("%02X", digest[i*4+j]); + } + putchar(' '); + } + putchar('\n'); + return(0); /* JHB */ +} +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/sha1.h b/Charcoal/Charcoal/libmobi-public/src/sha1.h new file mode 100644 index 0000000..6093006 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/sha1.h @@ -0,0 +1,27 @@ +/** @file sha1.h + * @brief Header for sha1.c + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_sha1_h +#define mobi_sha1_h + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[64]; +} SHA1_CTX; + +#define SHA1_DIGEST_SIZE 20 + +void SHA1_Init(SHA1_CTX *context); +void SHA1_Update(SHA1_CTX *context, const uint8_t *data, const size_t len); +void SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE]); + +#endif /* sha1_h */ diff --git a/Charcoal/Charcoal/libmobi-public/src/structure.c b/Charcoal/Charcoal/libmobi-public/src/structure.c new file mode 100644 index 0000000..4ed6529 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/structure.c @@ -0,0 +1,566 @@ +/** @file structure.c + * @brief Data structures + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include "structure.h" +#include "debug.h" +#if defined(__BIONIC__) && !defined(SIZE_MAX) +#include /* for SIZE_MAX */ +#endif + +/** + @brief Initializer for MOBIArray structure + + It allocates memory for structure and for data: array of uint32_t variables. + Memory should be freed with array_free(). + + @param[in] len Initial size of the array + @return MOBIArray on success, NULL otherwise + */ +MOBIArray * array_init(const size_t len) { + MOBIArray *arr = NULL; + arr = malloc(sizeof(MOBIArray)); + if (arr == NULL) { + debug_print("%s", "Array allocation failed\n"); + return NULL; + } + arr->data = malloc(len * sizeof(*arr->data)); + if (arr->data == NULL) { + free(arr); + debug_print("%s", "Array data allocation failed\n"); + return NULL; + } + arr->maxsize = len; + arr->step = len ? len : 1; + arr->size = 0; + return arr; +} + +/** + @brief Inserts value into MOBIArray array + + @param[in,out] arr MOBIArray array + @param[in] value Value to be inserted + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET array_insert(MOBIArray *arr, const uint32_t value) { + if (!arr || arr->maxsize == 0) { + return MOBI_INIT_FAILED; + } + if (arr->maxsize == arr->size) { + arr->maxsize += arr->step; + uint32_t *tmp = realloc(arr->data, arr->maxsize * sizeof(*arr->data)); + if (!tmp) { + free(arr->data); + arr->data = NULL; + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + arr->data = tmp; + } + arr->data[arr->size] = value; + arr->size++; + return MOBI_SUCCESS; +} + +/** + @brief Helper for qsort in array_sort() function. + + @param[in] a First element to compare + @param[in] b Second element to compare + @return -1 if a < b; 1 if a > b; 0 if a = b + */ +static int array_compare(const void *a, const void *b) { + if (*(uint32_t *) a < *(uint32_t *) b) { + return -1; + }; + if (*(uint32_t *) a > *(uint32_t *) b) { + return 1; + }; + return 0; +} + +/** + @brief Sort MOBIArray in ascending order. + + When unique is set to true, duplicate values are discarded. + + @param[in,out] arr MOBIArray array + @param[in] unique Discard duplicate values if true + */ +void array_sort(MOBIArray *arr, const bool unique) { + if (!arr || !arr->data || arr->size == 0) { + return; + } + qsort(arr->data, arr->size, sizeof(*arr->data), array_compare); + if (unique) { + size_t i = 1; + size_t j = 1; + while (i < arr->size) { + if (arr->data[j - 1] == arr->data[i]) { + i++; + continue; + } + arr->data[j++] = arr->data[i++]; + } + arr->size = j; + } +} + +/** + @brief Get size of the array + + @param[in] arr MOBIArray structure + @return Array size + */ +size_t array_size(MOBIArray *arr) { + return arr->size; +} + +/** + @brief Free MOBIArray structure and contained data + + Free data initialized with array_init(); + + @param[in] arr MOBIArray structure + */ +void array_free(MOBIArray *arr) { + if (!arr) { return; } + if (arr->data) { + free(arr->data); + } + free(arr); +} + + +/** + @brief Create and return MOBITrie structure + + @return MOBITrie stucture initialized with zeroes + */ +static MOBITrie * mobi_trie_mknode(void) { + MOBITrie *node = calloc(1, sizeof(MOBITrie)); + if (node == NULL) { + debug_print("Memory allocation failed%s", "\n"); + } + return node; +} + +/** + @brief Recursively free MOBITrie trie starting from node + + @param[in] node Starting node + */ +void mobi_trie_free(MOBITrie *node) { + if (node) { + mobi_trie_free(node->next); + mobi_trie_free(node->children); + free(node->values); + free(node); + } +} + +/** + @brief Insert value into array at given MOBITrie node + + @param[in,out] node Starting node + @param[in] value Value to be inserted + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_trie_addvalue(MOBITrie *node, char *value) { + if (node->values) { + size_t cnt = ++node->values_count; + void *new_values = realloc(node->values, cnt * sizeof(*node->values)); + if (new_values == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + node->values = new_values; + node->values[cnt - 1] = value; + } else { + node->values = malloc(sizeof(*node->values)); + if (node->values == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + node->values[0] = value; + node->values_count = 1; + } + return MOBI_SUCCESS; +} + +/** + @brief Insert key character and value (if given) at MOBITrie node + + @param[in,out] node Starting node + @param[in] c Key character + @param[in] value Value to be inserted at terminal node, or NULL if not terminal + @return MOBITrie node: current node if value inserted (terminal), + children node (if transitional) or NULL on error + */ +static MOBITrie * mobi_trie_insert_char(MOBITrie *node, char c, char *value) { + if (!node) { return NULL; } + while (true) { + if (node->c == c) { + break; + } + if (node->next == NULL) { + node->next = mobi_trie_mknode(); + node = node->next; + break; + } + node = node->next; + } + if (node->c == 0) { + node->c = c; + } + if (value) { + /* terminal node */ + if (mobi_trie_addvalue(node, value) == MOBI_SUCCESS) { + return node; + } + return NULL; + } + if (node->children == NULL) { + node->children = mobi_trie_mknode(); + } + return node->children; +} + +/** + @brief Insert reversed string into MOBITrie trie + + @param[in,out] root Root node + @param[in] string String to be inserted + @param[in] value Value associated with the string + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_trie_insert_reversed(MOBITrie **root, char *string, char *value) { + size_t length = strlen(string); + if (length == 0) { + debug_print("Skipping empty lookup string in trie node%s", "\n"); + return MOBI_SUCCESS; + } + if (*root == NULL) { + *root = mobi_trie_mknode(); + if (*root == NULL) { + return MOBI_MALLOC_FAILED; + } + } + MOBITrie *node = *root; + while (length > 1) { + node = mobi_trie_insert_char(node, string[length - 1], NULL); + if (node == NULL) { + return MOBI_MALLOC_FAILED; + } + length--; + } + node = mobi_trie_insert_char(node, string[length - 1], value); + if (node == NULL) { + return MOBI_MALLOC_FAILED; + } + return MOBI_SUCCESS; +} + +/** + @brief Fetch values for key c from MOBITrie trie's current level starting at node + + @param[in,out] values Array of values to be fetched + @param[in,out] values_count Array size + @param[in] node MOBITrie node to start search + @param[in] c Key character + @return MOBITrie children node of the node with c key or NULL if not found + */ +MOBITrie * mobi_trie_get_next(char ***values, size_t *values_count, const MOBITrie *node, const char c) { + if (!node) { return NULL; } + while (node) { + if (node->c == c) { + *values = (char**) node->values; + *values_count = node->values_count; + return node->children; + } + node = node->next; + } + return NULL; +} + +#if 0 +/* Simple imprementation of binary tree, storing key strings + and associated arrays of values + currently not used, save for later */ + +typedef struct MOBIBtree { + char *key; /**< key */ + char **array; /**< array of strings */ + size_t value_count; /**< strings count */ + struct MOBIBtree *left; /**< left child */ + struct MOBIBtree *right; /**< right child */ +} MOBIBtree; + +/** + @brief Search MOBIBtree tree for string key + + @param[in] node MOBIBtree node to start search + @param[in] key Key string + @return MOBIBtree node or NULL if not found + */ +MOBIBtree *mobi_btree_search(MOBIBtree *node, const char *key) { + MOBIBtree *found = NULL; + int compare = strcmp(key, node->key); + if (compare < 0) { + found = mobi_btree_search(node->left, key); + } else if (compare > 0) { + found = mobi_btree_search(node->right, key); + } else { + found = node; + } + return found; +} + +/** + @brief Insert key and value (into array) into MOBIBtree tree + + @param[in] node MOBIBtree root node + @param[in] key Key string + @param[in] value Value string will be inserted into array + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_btree_insert(MOBIBtree **node, char *key, char *value) { + MOBI_RET ret = MOBI_SUCCESS; + if (*node == NULL) { + *node = malloc(sizeof(MOBIBtree)); + if (*node == NULL) { + return MOBI_MALLOC_FAILED; + } + (*node)->key = key; + (*node)->value_count = 1; + (*node)->array = malloc(sizeof(*(*node)->array)); + if ((*node)->array == NULL) { + free(*node); + return MOBI_MALLOC_FAILED; + } + (*node)->array[0] = value; + (*node)->left = NULL; + (*node)->right = NULL; + return MOBI_SUCCESS; + } + int compare = strcmp(key, (*node)->key); + if (compare < 0) { + ret = mobi_btree_insert(&(*node)->left, key, value); + } else if (compare > 0) { + ret = mobi_btree_insert(&(*node)->right, key, value); + } else { + size_t cnt = ++(*node)->value_count; + char **new_array = realloc((*node)->array, cnt * sizeof(*(*node)->array)); + if (new_array) { + (*node)->array = new_array; + (*node)->array[cnt - 1] = value; + } else { + return MOBI_MALLOC_FAILED; + } + } + return ret; +} +#endif + + +/** + @brief Allocate fragment, fill with data and return + + @param[in] raw_offset Fragment offset in raw markup, + SIZE_MAX if not present in original markup + @param[in] fragment Fragment data + @param[in] size Size data + @param[in] is_malloc is_maloc data + @return Fragment structure filled with data + */ +static MOBIFragment * mobi_list_init(size_t raw_offset, unsigned char *fragment, const size_t size, const bool is_malloc) { + MOBIFragment *curr = calloc(1, sizeof(MOBIFragment)); + if (curr == NULL) { + if (is_malloc) { + free(fragment); + } + return NULL; + } + curr->raw_offset = raw_offset; + curr->fragment = fragment; + curr->size = size; + curr->is_malloc = is_malloc; + return curr; +} + +/** + @brief Allocate fragment, fill with data, append to linked list + + @param[in] curr Last fragment in linked list + @param[in] raw_offset Fragment offset in raw markup, + SIZE_MAX if not present in original markup + @param[in] fragment Fragment data + @param[in] size Size data + @param[in] is_malloc is_maloc data + @return Fragment structure filled with data + */ +MOBIFragment * mobi_list_add(MOBIFragment *curr, size_t raw_offset, unsigned char *fragment, const size_t size, const bool is_malloc) { + if (!curr) { + return mobi_list_init(raw_offset, fragment, size, is_malloc); + } + curr->next = calloc(1, sizeof(MOBIFragment)); + if (curr->next == NULL) { + if (is_malloc) { + free(fragment); + } + return NULL; + } + MOBIFragment *next = curr->next; + next->raw_offset = raw_offset; + next->fragment = fragment; + next->size = size; + next->is_malloc = is_malloc; + return next; +} + +/** + @brief Allocate fragment, fill with data, + insert into linked list at given offset + + Starts to search for offset at given fragment. The pointer to input fragment will be replaced by newly added one. + + @param[in,out] fragment Fragment where search starts, on success pointer to new fragment structure filled with data + @param[in] raw_offset Fragment offset in raw markup, SIZE_MAX if not present in original markup + @param[in] data Fragment data + @param[in] size Size data + @param[in] is_malloc is_maloc data + @param[in] offset offset where new chunk will be inserted + @return MOBI_RET status code (on success MOBI_SUCCESS, on offset not found MOBI_DATA_CORRUPT) + */ +MOBI_RET mobi_list_insert(MOBIFragment **fragment, size_t raw_offset, unsigned char *data, const size_t size, const bool is_malloc, const size_t offset) { + MOBIFragment *curr = *fragment; + MOBIFragment *prev = NULL; + while (curr) { + if (curr->raw_offset != SIZE_MAX && curr->raw_offset <= offset && curr->raw_offset + curr->size >= offset ) { + break; + } + prev = curr; + curr = curr->next; + } + if (!curr) { + debug_print("Offset not found: %zu\n", offset); + if (is_malloc) { + free(data); + } + return MOBI_DATA_CORRUPT; + } + MOBIFragment *new = calloc(1, sizeof(MOBIFragment)); + if (new == NULL) { + if (is_malloc) { + free(data); + } + return MOBI_MALLOC_FAILED; + } + new->raw_offset = raw_offset; + new->fragment = data; + new->size = size; + new->is_malloc = is_malloc; + MOBIFragment *new2 = NULL; + if (curr->raw_offset == offset) { + /* prepend chunk */ + if (prev) { + prev->next = new; + new->next = curr; + } else { + /* save curr */ + MOBIFragment tmp; + tmp.raw_offset = curr->raw_offset; + tmp.fragment = curr->fragment; + tmp.size = curr->size; + tmp.is_malloc = curr->is_malloc; + tmp.next = curr->next; + /* move new to curr */ + curr->raw_offset = new->raw_offset; + curr->fragment = new->fragment; + curr->size = new->size; + curr->is_malloc = new->is_malloc; + curr->next = new; + /* restore tmp to new */ + new->raw_offset = tmp.raw_offset; + new->fragment = tmp.fragment; + new->size = tmp.size; + new->is_malloc = tmp.is_malloc; + new->next = tmp.next; + *fragment = curr; + return MOBI_SUCCESS; + } + } else if (curr->raw_offset + curr->size == offset) { + /* append chunk */ + new->next = curr->next; + curr->next = new; + } else { + /* split fragment and insert new chunk */ + new2 = calloc(1, sizeof(MOBIFragment)); + if (new2 == NULL) { + free(new); + if (is_malloc) { + free(data); + } + return MOBI_MALLOC_FAILED; + } + size_t rel_offset = offset - curr->raw_offset; + new2->next = curr->next; + new2->size = curr->size - rel_offset; + new2->raw_offset = offset; + new2->fragment = curr->fragment + rel_offset; + new2->is_malloc = false; + curr->next = new; + curr->size = rel_offset; + new->next = new2; + } + /* correct offsets */ + if (raw_offset != SIZE_MAX) { + curr = new->next; + while (curr) { + if (curr->raw_offset != SIZE_MAX) { + curr->raw_offset += new->size; + } + curr = curr->next; + } + } + *fragment = new; + return MOBI_SUCCESS; +} + +/** + @brief Delete fragment from linked list + + @param[in] curr Fragment to be deleted + @return Next fragment in the linked list or NULL if absent + */ +MOBIFragment * mobi_list_del(MOBIFragment *curr) { + MOBIFragment *del = curr; + curr = curr->next; + if (del->is_malloc) { + free(del->fragment); + } + free(del); + del = NULL; + return curr; +} + +/** + @brief Delete all fragments from linked list + + @param[in] first First fragment from the list + */ +void mobi_list_del_all(MOBIFragment *first) { + while (first) { + first = mobi_list_del(first); + } +} diff --git a/Charcoal/Charcoal/libmobi-public/src/structure.h b/Charcoal/Charcoal/libmobi-public/src/structure.h new file mode 100644 index 0000000..0c65320 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/structure.h @@ -0,0 +1,66 @@ +/** @file structure.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_structure_h +#define mobi_structure_h + +#include "config.h" +#include "mobi.h" + +/** + @brief Dynamic array of uint32_t values structure + */ +typedef struct { + uint32_t *data; /**< Array */ + size_t maxsize; /**< Allocated size */ + size_t step; /**< Step by which array will be enlarged if out of memory */ + size_t size; /**< Current size */ +} MOBIArray; + +MOBIArray * array_init(const size_t len); +MOBI_RET array_insert(MOBIArray *arr, const uint32_t value); +void array_sort(MOBIArray *arr, const bool unique); +size_t array_size(MOBIArray *arr); +void array_free(MOBIArray *arr); + +/** + @brief Trie storing arrays of values for character keys + */ +typedef struct MOBITrie { + char c; /**< Key character */ + void **values; /**< Array of values */ + size_t values_count; /**< Array size */ + struct MOBITrie *next; /**< Next node at the same level */ + struct MOBITrie *children; /**< Link to children nodes, lower level */ +} MOBITrie; + +MOBI_RET mobi_trie_insert_reversed(MOBITrie **root, char *string, char *value); +MOBITrie * mobi_trie_get_next(char ***values, size_t *values_count, const MOBITrie *node, const char c); +void mobi_trie_free(MOBITrie *node); + +/** + @brief Structure for links reconstruction. + + Linked list of Fragment structures forms whole document part + */ +typedef struct MOBIFragment { + size_t raw_offset; /**< fragment offset in raw markup, SIZE_MAX if not present in original markup */ + unsigned char *fragment; /**< Fragment data */ + size_t size; /**< Fragment size */ + bool is_malloc; /**< Is it needed to free this fragment or is it just an alias to part data */ + struct MOBIFragment *next; /**< Link to next fragment */ +} MOBIFragment; + +MOBIFragment * mobi_list_add(MOBIFragment *curr, size_t raw_offset, unsigned char *fragment, const size_t size, const bool is_malloc); +MOBIFragment * mobi_list_del(MOBIFragment *curr); +MOBI_RET mobi_list_insert(MOBIFragment **curr, size_t raw_offset, unsigned char *fragment, const size_t size, const bool is_malloc, const size_t offset); +void mobi_list_del_all(MOBIFragment *first); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/util.c b/Charcoal/Charcoal/libmobi-public/src/util.c new file mode 100644 index 0000000..acc5b77 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/util.c @@ -0,0 +1,3561 @@ +/** @file util.c + * @brief Various helper functions + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#define _GNU_SOURCE 1 +#ifndef __USE_BSD +#define __USE_BSD /* for strdup on linux/glibc */ +#endif + +#include +#include +#include +#include "util.h" +#include "parse_rawml.h" +#include "index.h" +#include "debug.h" + +#ifdef USE_ENCRYPTION +#include "encryption.h" +#endif + +#ifdef USE_XMLWRITER +#include "opf.h" +#endif + +#define MOBI_FONT_OBFUSCATED_BUFFER_COUNT 52 + +/** @brief Lookup table for cp1252 to utf8 encoding conversion */ +static const unsigned char cp1252_to_utf8[32][3] = { + {0xe2,0x82,0xac}, + {0}, + {0xe2,0x80,0x9a}, + {0xc6,0x92,0}, + {0xe2,0x80,0x9e}, + {0xe2,0x80,0xa6}, + {0xe2,0x80,0xa0}, + {0xe2,0x80,0xa1}, + {0xcb,0x86,0}, + {0xe2,0x80,0xb0}, + {0xc5,0xa0,0}, + {0xe2,0x80,0xb9}, + {0xc5,0x92,0}, + {0}, + {0xc5,0xbd,0}, + {0}, + {0}, + {0xe2,0x80,0x98}, + {0xe2,0x80,0x99}, + {0xe2,0x80,0x9c}, + {0xe2,0x80,0x9d}, + {0xe2,0x80,0xa2}, + {0xe2,0x80,0x93}, + {0xe2,0x80,0x94}, + {0xcb,0x9c,0}, + {0xe2,0x84,0xa2}, + {0xc5,0xa1,0}, + {0xe2,0x80,0xba}, + {0xc5,0x93,0}, + {0}, + {0xc5,0xbe,0}, + {0xc5,0xb8,0}, +}; + +/** + @brief Get libmobi version + + @return String version + */ +const char * mobi_version(void) { +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "unknown" +#endif + return PACKAGE_VERSION; +} + +/** + @brief Convert unicode codepoint to utf-8 sequence + + @param[in,out] output Output string + @param[in] codepoint Unicode codepoint + @return Length of utf-8 sequence (maximum 4 bytes), zero on failure + */ +uint8_t mobi_unicode_to_utf8(char *output, const size_t codepoint) { + if (!output) { + return 0; + } + unsigned char *bytes = (unsigned char *) output; + + if (codepoint < 0x80) { + bytes[0] = (unsigned char) codepoint; + return 1; + } + if (codepoint < 0x800) { + bytes[1] = (unsigned char) ((2 << 6) | (codepoint & 0x3f)); + bytes[0] = (unsigned char) ((6 << 5) | (codepoint >> 6)); + return 2; + } + if (codepoint < 0x10000) { + bytes[2] = (unsigned char) ((2 << 6) | (codepoint & 0x3f)); + bytes[1] = (unsigned char) ((2 << 6) | ((codepoint >> 6) & 0x3f)); + bytes[0] = (unsigned char) ((14 << 4) | (codepoint >> 12)); + return 3; + } + if (codepoint < 0x11000) { + bytes[3] = (unsigned char) ((2 << 6) | (codepoint & 0x3f)); + bytes[2] = (unsigned char) ((2 << 6) | ((codepoint >> 6) & 0x3f)); + bytes[1] = (unsigned char) ((2 << 6) | ((codepoint >> 12) & 0x3f)); + bytes[0] = (unsigned char) ((30 << 3) | (codepoint >> 18)); + return 4; + } + return 0; +} + +/** + @brief Convert cp1252 encoded string to utf-8 + + Maximum length of output string is 3 * (input string length) + 1 + Output string will be null terminated (even if truncated) + + @param[in,out] output Output string + @param[in,out] input Input string + @param[in,out] outsize Size of the allocated output buffer, will be set to output string length (without null terminator) on return + @param[in] insize Length of the input string. + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_cp1252_to_utf8(char *output, const char *input, size_t *outsize, const size_t insize) { + if (!output || !input) { + return MOBI_PARAM_ERR; + } + const unsigned char *in = (unsigned char *) input; + unsigned char *out = (unsigned char *) output; + const unsigned char *outend = out + *outsize - 1; /* leave space for null terminator */ + const unsigned char *inend = in + insize; + while (in < inend && out < outend && *in) { + if (*in < 0x80) { + *out++ = *in++; + } + else if (*in < 0xa0) { + /* table lookup */ + size_t i = 0; + while (i < 3 && out < outend) { + unsigned char c = cp1252_to_utf8[*in - 0x80][i]; + if (c == 0) { + break; + } + *out++ = c; + i++; + } + if (i == 0) { + /* unmappable character in input */ + /* substitute with utf-8 replacement character */ + if (out >= outend - 1) { break; } + *out++ = 0xff; + *out++ = 0xfd; + debug_print("Invalid character found: %c\n", *in); + } + in++; + } + else if (*in < 0xc0) { + if (out >= outend - 1) { break; } + *out++ = 0xc2; + *out++ = *in++; + } + else { + if (out >= outend - 1) { break; } + *out++ = 0xc3; + *out++ = (*in++ & 0x3f) + 0x80; + } + } + *out = '\0'; + *outsize = (size_t) (out - (unsigned char *) output); + return MOBI_SUCCESS; +} + +/** + @brief Convert utf-8 encoded string to cp1252 + + Characters out of range will be replaced with substitute character + + @param[in,out] output Output string + @param[in,out] input Input string + @param[in,out] outsize Size of the allocated output buffer, will be set to output string length (without null terminator) on return + @param[in] insize Length of the input string. + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_utf8_to_cp1252(char *output, const char *input, size_t *outsize, const size_t insize) { + if (!output || !input) { + return MOBI_PARAM_ERR; + } + const unsigned char *in = (unsigned char *) input; + unsigned char *out = (unsigned char *) output; + const unsigned char *outend = out + *outsize - 1; /* leave space for null terminator */ + const unsigned char *inend = in + insize; + while (in < inend && out < outend && *in) { + /* one byte */ + if (*in < 0x80) { + *out++ = *in++; + } + /* two bytes */ + else if ((*in & 0xe0) == 0xc0) { + if (in > inend - 2) { break; } + if (in[0] == 0xc2 && (in[1] >= 0xa0 && in[1] <= 0xbf)) { + *out++ = in[1]; + } else if (in[0] == 0xc3 && (in[1] >= 0x80 && in[1] <= 0xbf)) { + *out++ = in[1] + 0x40; + } else if (in[0] == 0xc5) { + switch (in[1]) { + case 0xa0: + *out++ = 0x8a; + break; + case 0x92: + *out++ = 0x8c; + break; + case 0xbd: + *out++ = 0x8e; + break; + case 0xa1: + *out++ = 0x9a; + break; + case 0x93: + *out++ = 0x9c; + break; + case 0xbe: + *out++ = 0x9e; + break; + case 0xb8: + *out++ = 0x9f; + break; + default: + *out++ = '?'; + break; + } + } else if (in[0] == 0xc6 && in[1] == 0x92) { + *out++ = 0x83; + } else if (in[0] == 0xcb && in[1] == 0x86) { + *out++ = 0x88; + } else { + *out++ = '?'; + } + in += 2; + } + /* three bytes */ + else if ((*in & 0xf0) == 0xe0) { + if (in > inend - 3) { break; } + if (in[0] == 0xe2 && in[1] == 0x80) { + switch (in[2]) { + case 0x9a: + *out++ = 0x82; + break; + case 0x9e: + *out++ = 0x84; + break; + case 0xa6: + *out++ = 0x85; + break; + case 0xa0: + *out++ = 0x86; + break; + case 0xb0: + *out++ = 0x89; + break; + case 0xb9: + *out++ = 0x8b; + break; + case 0x98: + *out++ = 0x91; + break; + case 0x99: + *out++ = 0x92; + break; + case 0x9c: + *out++ = 0x93; + break; + case 0x9d: + *out++ = 0x94; + break; + case 0xa2: + *out++ = 0x95; + break; + case 0x93: + *out++ = 0x86; + break; + case 0x94: + *out++ = 0x97; + break; + case 0xba: + *out++ = 0x9b; + break; + default: + *out++ = '?'; + break; + } + } else if (in[0] == 0xe2 && in[1] == 0x82 && in[2] == 0xac) { + *out++ = 0x80; + } else if (in[0] == 0xe2 && in[1] == 0x84 && in[2] == 0xa2) { + *out++ = 0x99; + } else { + *out++ = '?'; + } + in += 3; + } + /* four bytes */ + else if ((*in & 0xf8) == 0xf0) { + if (in > inend - 4) { break; } + *out++ = '?'; + in += 4; + } + /* skip error */ + else { + *out++ = '?'; + in++; + } + } + *out = '\0'; + *outsize = (size_t) (out - (unsigned char *) output); + return MOBI_SUCCESS; +} + +/** @brief Decode ligature to cp1252 + + Some latin ligatures are encoded in indices to facilitate search + They are listed in LIGT header, but it seems every LIGT header contains + same 5 ligatures (even if not all of them are used). + So, instead of parsing header, we use static replacements. + Invalid control characters are skipped + + @param[in] byte1 First byte - control character + @param[in] byte2 Second byte of the ligature + @return Ligature in cp1252 encoding, zero if not found + */ +uint8_t mobi_ligature_to_cp1252(const uint8_t byte1, const uint8_t byte2) { + uint8_t ligature = 0; + const uint8_t lig_OE = 0x8c; + const uint8_t lig_oe = 0x9c; + const uint8_t lig_AE = 0xc6; + const uint8_t lig_ae = 0xe6; + const uint8_t lig_ss = 0xdf; + switch (byte1) { + case 1: + if (byte2 == 0x45) { ligature = lig_OE; } + break; + case 2: + if (byte2 == 0x65) { ligature = lig_oe; } + break; + case 3: + if (byte2 == 0x45) { ligature = lig_AE; } + break; + case 4: + if (byte2 == 0x65) { ligature = lig_ae; } + break; + case 5: + if (byte2 == 0x73) { ligature = lig_ss; } + break; + } + return ligature; +} + +/** @brief Decode ligature to utf-16 + + @param[in] byte1 First byte - control character, should be <= 5 + @param[in] byte2 Second byte of the ligature + @return Ligature in utf-16 encoding, uni_replacement if not found + */ +uint16_t mobi_ligature_to_utf16(const uint32_t byte1, const uint32_t byte2) { + const uint16_t uni_replacement = 0xfffd; + uint16_t ligature = uni_replacement; + const uint16_t lig_OE = 0x152; + const uint16_t lig_oe = 0x153; + const uint16_t lig_AE = 0xc6; + const uint16_t lig_ae = 0xe6; + const uint16_t lig_ss = 0xdf; + switch (byte1) { + case 1: + if (byte2 == 0x45) { ligature = lig_OE; } + break; + case 2: + if (byte2 == 0x65) { ligature = lig_oe; } + break; + case 3: + if (byte2 == 0x45) { ligature = lig_AE; } + break; + case 4: + if (byte2 == 0x65) { ligature = lig_ae; } + break; + case 5: + if (byte2 == 0x73) { ligature = lig_ss; } + break; + } + return ligature; +} + +/** @brief Get text encoding of mobi document + + @param[in] m MOBIData structure holding document data and metadata + @return MOBIEncoding text encoding (MOBI_UTF8 or MOBI_CP1252) + */ +MOBIEncoding mobi_get_encoding(const MOBIData *m) { + if (m && m->mh) { + if (m->mh->text_encoding) { + if (*m->mh->text_encoding == MOBI_UTF8) { + return MOBI_UTF8; + } + } + } + return MOBI_CP1252; +} + +/** @brief Check if document's text is cp1252 encoded + + @param[in] m MOBIData structure holding document data and metadata + @return True or false + */ +bool mobi_is_cp1252(const MOBIData *m) { + return (mobi_get_encoding(m) == MOBI_CP1252); +} + +/** + @brief strdup replacement + + Returned pointer must be freed by caller + + @param[in] s Input string + @return Duplicated string + */ +char * mobi_strdup(const char *s) { + char *p = malloc(strlen(s) + 1); + if (p) { strcpy(p, s); } + return p; +} + +#define MOBI_LANG_MAX 99 /**< number of entries in mobi_locale array */ +#define MOBI_REGION_MAX 21 /**< maximum number of entries in each language array */ + +/**< @brief Table of Mobipocket language-region codes + + Based on IANA language-subtag registry with some custom Mobipocket modifications. + http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry + */ +static const char *mobi_locale[MOBI_LANG_MAX][MOBI_REGION_MAX] = { + {"neutral"}, + { + "ar", /**< Arabic >*/ + "ar-sa", /**< Arabic (Saudi Arabia) >*/ + "ar", /**< Arabic (Unknown) */ + "ar-eg", /**< Arabic (Egypt) >*/ + "ar", /**< Arabic (Unknown) */ + "ar-dz", /**< Arabic (Algeria) >*/ + "ar-ma", /**< Arabic (Morocco) >*/ + "ar-tn", /**< Arabic (Tunisia) >*/ + "ar-om", /**< Arabic (Oman) >*/ + "ar-ye", /**< Arabic (Yemen) >*/ + "ar-sy", /**< Arabic (Syria) >*/ + "ar-jo", /**< Arabic (Jordan) >*/ + "ar-lb", /**< Arabic (Lebanon) >*/ + "ar-kw", /**< Arabic (Kuwait) >*/ + "ar-ae", /**< Arabic (UAE) >*/ + "ar-bh", /**< Arabic (Bahrain) >*/ + "ar-qa", /**< Arabic (Qatar) >*/ + }, + {"bg"}, /**< Bulgarian >*/ + {"ca"}, /**< Catalan >*/ + { + "zh", /**< Chinese >*/ + "zh-tw", /**< Chinese (Taiwan) >*/ + "zh-cn", /**< Chinese (PRC) >*/ + "zh-hk", /**< Chinese (Hong Kong) >*/ + "zh-sg", /**< Chinese (Singapore) >*/ + }, + {"cs"}, /**< Czech >*/ + {"da"}, /**< Danish >*/ + { + "de", /**< German >*/ + "de-de", /**< German (Germany) >*/ + "de-ch", /**< German (Switzerland) >*/ + "de-at", /**< German (Austria) >*/ + "de-lu", /**< German (Luxembourg) >*/ + "de-li", /**< German (Liechtenstein) >*/ + }, + {"el"}, /**< Greek (modern) >*/ + { + "en", /**< English >*/ + "en-us", /**< English (United States) >*/ + "en-gb", /**< English (United Kingdom) >*/ + "en-au", /**< English (Australia) >*/ + "en-ca", /**< English (Canada) >*/ + "en-nz", /**< English (New Zealand) >*/ + "en-ie", /**< English (Ireland) >*/ + "en-za", /**< English (South Africa) >*/ + "en-jm", /**< English (Jamaica) >*/ + "en", /**< English (Unknown) >*/ + "en-bz", /**< English (Belize) >*/ + "en-tt", /**< English (Trinidad) >*/ + "en-zw", /**< English (Zimbabwe) >*/ + "en-ph", /**< English (Philippines) >*/ + }, + { + "es", /**< Spanish >*/ + "es-es", /**< Spanish (Spain) >*/ + "es-mx", /**< Spanish (Mexico) >*/ + "es", /**< Spanish (Unknown) >*/ + "es-gt", /**< Spanish (Guatemala) >*/ + "es-cr", /**< Spanish (Costa Rica) >*/ + "es-pa", /**< Spanish (Panama) >*/ + "es-do", /**< Spanish (Dominican Republic) >*/ + "es-ve", /**< Spanish (Venezuela) >*/ + "es-co", /**< Spanish (Colombia) >*/ + "es-pe", /**< Spanish (Peru) >*/ + "es-ar", /**< Spanish (Argentina) >*/ + "es-ec", /**< Spanish (Ecuador) >*/ + "es-cl", /**< Spanish (Chile) >*/ + "es-uy", /**< Spanish (Uruguay) >*/ + "es-py", /**< Spanish (Paraguay) >*/ + "es-bo", /**< Spanish (Bolivia) >*/ + "es-sv", /**< Spanish (El Salvador) >*/ + "es-hn", /**< Spanish (Honduras) >*/ + "es-ni", /**< Spanish (Nicaragua) >*/ + "es-pr", /**< Spanish (Puerto Rico) >*/ + }, + {"fi"}, /**< Finnish >*/ + { + "fr", /**< French >*/ + "fr-fr", /**< French (France) >*/ + "fr-be", /**< French (Belgium) >*/ + "fr-ca", /**< French (Canada) >*/ + "fr-ch", /**< French (Switzerland) >*/ + "fr-lu", /**< French (Luxembourg) >*/ + "fr-mc", /**< French (Monaco) >*/ + }, + {"he"}, /**< Hebrew (also code iw) >*/ + {"hu"}, /**< Hungarian >*/ + {"is"}, /**< Icelandic >*/ + { + "it", /**< Italian >*/ + "it-it", /**< Italian (Italy) >*/ + "it-ch", /**< Italian (Switzerland) >*/ + }, + {"ja"}, /**< Japanese >*/ + {"ko"}, /**< Korean >*/ + { + "nl", /**< Dutch / Flemish >*/ + "nl-nl", /**< Dutch (Netherlands) >*/ + "nl-be", /**< Dutch (Belgium) >*/ + }, + {"no"}, /**< Norwegian >*/ + {"pl"}, /**< Polish >*/ + { + "pt", /**< Portuguese >*/ + "pt-br", /**< Portuguese (Brazil) >*/ + "pt-pt", /**< Portuguese (Portugal) >*/ + }, + {"rm"}, /**< Romansh >*/ + {"ro"}, /**< Romanian >*/ + {"ru"}, /**< Russian >*/ + { + "hr", /**< Croatian >*/ + "sr", /**< Serbian >*/ + "sr", /**< Serbian (Unknown) >*/ + "sr", /**< Serbian (Unknown) >*/ + "sr", /**< Serbian (Serbia) >*/ + }, + {"sk"}, /**< Slovak >*/ + {"sq"}, /**< Albanian >*/ + { + "sv", /**< Swedish >*/ + "sv-se", /**< Swedish (Sweden) >*/ + "sv-fi", /**< Swedish (Finland) >*/ + }, + {"th"}, /**< Thai >*/ + {"tr"}, /**< Turkish >*/ + {"ur"}, /**< Urdu >*/ + {"id"}, /**< Indonesian >*/ + {"uk"}, /**< Ukrainian >*/ + {"be"}, /**< Belarusian >*/ + {"sl"}, /**< Slovenian >*/ + {"et"}, /**< Estonian >*/ + {"lv"}, /**< Latvian >*/ + {"lt"}, /**< Lithuanian >*/ + [41] = {"fa"}, /**< Farsi / Persian >*/ + {"vi"}, /**< Vietnamese >*/ + {"hy"}, /**< Armenian >*/ + {"az"}, /**< Azerbaijani >*/ + {"eu"}, /**< Basque >*/ + {"sb"}, /**< "Sorbian" >*/ + {"mk"}, /**< Macedonian >*/ + {"sx"}, /**< "Sutu" >*/ + {"ts"}, /**< Tsonga >*/ + {"tn"}, /**< Tswana >*/ + [52] = {"xh"}, /**< Xhosa >*/ + {"zu"}, /**< Zulu >*/ + {"af"}, /**< Afrikaans >*/ + {"ka"}, /**< Georgian >*/ + {"fo"}, /**< Faroese >*/ + {"hi"}, /**< Hindi >*/ + {"mt"}, /**< Maltese >*/ + {"sz"}, /**<"Sami (Lappish)" >*/ + {"ga"}, /**< Irish */ + [62] = {"ms"}, /**< Malay >*/ + {"kk"}, /**< Kazakh >*/ + [65] = {"sw"}, /**< Swahili >*/ + [67] = { + "uz", /**< Uzbek >*/ + "uz", /**< Uzbek (Unknown) >*/ + "uz-uz", /**< Uzbek (Uzbekistan) >*/ + }, + {"tt"}, /**< Tatar >*/ + {"bn"}, /**< Bengali >*/ + {"pa"}, /**< Punjabi >*/ + {"gu"}, /**< Gujarati >*/ + {"or"}, /**< Oriya >*/ + {"ta"}, /**< Tamil >*/ + {"te"}, /**< Telugu >*/ + {"kn"}, /**< Kannada >*/ + {"ml"}, /**< Malayalam >*/ + {"as"}, /**< Assamese (not accepted in kindlegen >*/ + {"mr"}, /**< Marathi >*/ + {"sa"}, /**< Sanskrit >*/ + [82] = { + "cy", /**< Welsh */ + "cy-gb" /**< Welsh (UK) */ + }, + { + "gl", /**< Galician */ + "gl-es" /**< Galician (Spain) */ + }, + [87] = {"x-kok"}, /**< Konkani (real language code is kok) >*/ + [97] = {"ne"}, /**< Nepali >*/ + {"fy"}, /**< Northern Frysian >*/ +}; + +/** + @brief Get pointer to locale tag for a given Mobipocket locale number + + Locale strings are based on IANA language-subtag registry with some custom Mobipocket modifications. + See mobi_locale array. + + @param[in] locale_number Mobipocket locale number (as stored in MOBI header) + @return Pointer to locale string in mobi_locale array or NULL on error + */ +const char * mobi_get_locale_string(const uint32_t locale_number) { + uint8_t lang_code = locale_number & 0xffU; + uint32_t region_code = (locale_number >> 8) / 4; + if (lang_code >= MOBI_LANG_MAX || region_code >= MOBI_REGION_MAX) { + return NULL; + } + const char *string = mobi_locale[lang_code][region_code]; + if (string == NULL || strlen(string) == 0 ) { + return NULL; + } + return string; +} + +/** + @brief Get Mobipocket locale number for a given string tag + + Locale strings are based on IANA language-subtag registry with some custom Mobipocket modifications. + See mobi_locale array. + + @param[in] locale_string Locale string tag + @return Mobipocket locale number + */ +size_t mobi_get_locale_number(const char *locale_string) { + if (locale_string == NULL || strlen(locale_string) < 2) { + return 0; + } + size_t lang_code = 0; + while (lang_code < MOBI_LANG_MAX) { + char *p = (char *) mobi_locale[lang_code][0]; + if (p == NULL) { + lang_code++; + continue; + } + + if (tolower(locale_string[0]) != p[0] || + tolower(locale_string[1]) != p[1]) { + lang_code++; + continue; + } + size_t region_code = 0; + while (region_code < MOBI_REGION_MAX) { + p = (char *) mobi_locale[lang_code][region_code]; + if (p == NULL) { break; } + for (int i = 2;; i++) { + if (tolower(locale_string[i]) != p[i]) { break; } + if (p[i] == 0) { + return (region_code * 4) << 8 | lang_code; + } + } + region_code++; + } + return lang_code; + } + return 0; +} + +/** + @brief Array of known file types, their extensions and mime-types. + */ +const MOBIFileMeta mobi_file_meta[] = { + {T_HTML, "html", "application/xhtml+xml"}, + {T_CSS, "css", "text/css"}, + {T_SVG, "svg", "image/svg+xml"}, + {T_JPG, "jpg", "image/jpeg"}, + {T_GIF, "gif", "image/gif"}, + {T_PNG, "png", "image/png"}, + {T_BMP, "bmp", "image/bmp"}, + {T_OTF, "otf", "application/vnd.ms-opentype"}, + {T_TTF, "ttf", "application/x-font-truetype"}, + {T_MP3, "mp3", "audio/mpeg"}, + {T_MPG, "mpg", "video/mpeg"}, + {T_PDF, "pdf", "application/pdf"}, + {T_OPF, "opf", "application/oebps-package+xml"}, + {T_NCX, "ncx", "application/x-dtbncx+xml"}, + /* termination struct */ + {T_UNKNOWN, "dat", "application/unknown"} +}; + +/** + @brief Get MOBIFileMeta tag structure by MOBIFiletype type + + @param[in] type MOBIFiletype type + @return MOBIExthMeta structure for given type, .type = T_UNKNOWN on failure + */ +MOBIFileMeta mobi_get_filemeta_by_type(const MOBIFiletype type) { + size_t i = 0; + while (mobi_file_meta[i].type != T_UNKNOWN) { + if (mobi_file_meta[i].type == type) { + return mobi_file_meta[i]; + } + i++; + } + return mobi_file_meta[i]; +} + +/** + @brief Get ebook full name stored in Record 0 at offset given in MOBI header + + @param[in] m MOBIData structure with loaded data + @param[in,out] fullname Memory area to be filled with zero terminated full name string + @param[in] len Maximum length of the string without null terminator + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_fullname(const MOBIData *m, char *fullname, const size_t len) { + if (fullname == NULL || len == 0) { + return MOBI_PARAM_ERR; + } + fullname[0] = '\0'; + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (m->mh == NULL || m->mh->full_name == NULL) { + return MOBI_INIT_FAILED; + } + if (mobi_is_cp1252(m)) { + size_t out_len = len + 1; + mobi_cp1252_to_utf8(fullname, m->mh->full_name, &out_len, strlen(m->mh->full_name)); + } else { + strncpy(fullname, m->mh->full_name, len); + fullname[len] = '\0'; + } + return MOBI_SUCCESS; +} + +/** + @brief Set ebook full name stored in Record 0 at offset given in MOBI header + + @param[in,out] m MOBIData structure with loaded data + @param[in] fullname Memory area to be filled with zero terminated full name string + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_set_fullname(MOBIData *m, const char *fullname) { + if (mobi_exists_mobiheader(m) && m->mh->full_name) { + size_t title_length = min(strlen(fullname), MOBI_TITLE_SIZEMAX); + char *new_title = malloc(title_length + 1); + if (new_title == NULL) { + return MOBI_MALLOC_FAILED; + } + if (mobi_is_cp1252(m)) { + size_t new_size = title_length + 1; + MOBI_RET ret = mobi_utf8_to_cp1252(new_title, fullname, &new_size, title_length); + if (ret != MOBI_SUCCESS) { + free(new_title); + return ret; + } + } else { + memcpy(new_title, fullname, title_length); + new_title[title_length] = '\0'; + } + free(m->mh->full_name); + m->mh->full_name = new_title; + if (mobi_is_hybrid(m) && mobi_exists_mobiheader(m->next) && m->next->mh->full_name) { + char *new_title2 = strdup(new_title); + if (new_title2 == NULL) { + return MOBI_MALLOC_FAILED; + } + free(m->next->mh->full_name); + m->next->mh->full_name = new_title2; + } + } + return MOBI_SUCCESS; +} + +/** + @brief Set palm database name + + @param[in,out] m MOBIData structure with loaded data + @param[in] name Name + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_set_pdbname(MOBIData *m, const char *name) { + if (m == NULL || m->ph == NULL) { + return MOBI_INIT_FAILED; + } + char dbname[PALMDB_NAME_SIZE_MAX + 1]; + if (mobi_is_cp1252(m)) { + size_t size = PALMDB_NAME_SIZE_MAX + 1; + MOBI_RET ret = mobi_utf8_to_cp1252(dbname, name, &size, strlen(name)); + if (ret != MOBI_SUCCESS) { + return ret; + } + } else { + memcpy(dbname, name, PALMDB_NAME_SIZE_MAX); + dbname[PALMDB_NAME_SIZE_MAX] = '\0'; + } + char c; + int i = 0; + while ((c = dbname[i])) { + if (!isalnum(c)) { + c = '_'; + } + m->ph->name[i++] = c; + } + m->ph->name[i] = '\0'; + return MOBI_SUCCESS; +} + +/** + @brief Get palm database record with given unique id + + @param[in] m MOBIData structure with loaded data + @param[in] uid Unique id + @return Pointer to MOBIPdbRecord record structure, NULL on failure + */ +MOBIPdbRecord * mobi_get_record_by_uid(const MOBIData *m, const size_t uid) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + if (m->rec == NULL) { + return NULL; + } + MOBIPdbRecord *curr = m->rec; + while (curr != NULL) { + if (curr->uid == uid) { + return curr; + } + curr = curr->next; + } + return NULL; +} + +/** + @brief Get rawml->markup MOBIPart part by uid + + @param[in] rawml MOBIRawml structure with loaded data + @param[in] uid Unique id + @return Pointer to MOBIPart structure, NULL on failure + */ +MOBIPart * mobi_get_part_by_uid(const MOBIRawml *rawml, const size_t uid) { + if (rawml == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + if (rawml->markup == NULL) { + return NULL; + } + MOBIPart *part = rawml->markup; + while (part != NULL) { + if (part->uid == uid) { + return part; + } + part = part->next; + } + return NULL; +} + +/** + @brief Get rawml->flow MOBIPart part by uid + + @param[in] rawml MOBIRawml structure with loaded data + @param[in] uid Unique id + @return Pointer to MOBIPart structure, NULL on failure + */ +MOBIPart * mobi_get_flow_by_uid(const MOBIRawml *rawml, const size_t uid) { + if (rawml == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + if (rawml->flow == NULL) { + return NULL; + } + MOBIPart *part = rawml->flow; + while (part != NULL) { + if (part->uid == uid) { + return part; + } + part = part->next; + } + return NULL; +} + +/** + @brief Find flow part by flow id (fid) from kindle:flow:fid link. + Flow fid is base32 encoded part uid. + + @param[in] rawml Structure MOBIRawml + @param[in] fid String four character base32 fid + @return Pointer to MOBIPart structure, NULL on failure + */ +MOBIPart * mobi_get_flow_by_fid(const MOBIRawml *rawml, const char *fid) { + /* get file number */ + uint32_t part_id; + MOBI_RET ret = mobi_base32_decode(&part_id, fid); + if (ret != MOBI_SUCCESS) { + return NULL; + } + return mobi_get_flow_by_uid(rawml, part_id); +} + +/** + @brief Get MOBIPart resource record with given unique id + + @param[in] rawml MOBIRawml structure with loaded data + @param[in] uid Unique id + @return Pointer to MOBIPart resource structure, NULL on failure + */ +MOBIPart * mobi_get_resource_by_uid(const MOBIRawml *rawml, const size_t uid) { + if (rawml == NULL) { + debug_print("%s", "Rawml structure not initialized\n"); + return NULL; + } + if (rawml->resources == NULL) { + debug_print("%s", "Rawml structure not initialized\n"); + return NULL; + } + MOBIPart *curr = rawml->resources; + while (curr != NULL) { + if (curr->uid == uid) { + return curr; + } + curr = curr->next; + } + return NULL; +} + +/** + @brief Find resource by flow id (fid) from kindle:embed:fid link. + Flow fid is base32 encoded part uid. + + @param[in] rawml Structure MOBIRawml + @param[in] fid String four character base32 fid + @return Pointer to MOBIPart structure, NULL on failure + */ +MOBIPart * mobi_get_resource_by_fid(const MOBIRawml *rawml, const char *fid) { + /* get file number */ + uint32_t part_id; + MOBI_RET ret = mobi_base32_decode(&part_id, fid); + if (ret != MOBI_SUCCESS) { + return NULL; + } + part_id--; + return mobi_get_resource_by_uid(rawml, part_id); +} + +/** + @brief Get MOBIFiletype type of MOBIPart resource record with given unique id + + @param[in] rawml MOBIRawml structure with loaded data + @param[in] uid Unique id + @return Pointer to MOBIPart resource structure, NULL on failure + */ +MOBIFiletype mobi_get_resourcetype_by_uid(const MOBIRawml *rawml, const size_t uid) { + if (rawml == NULL) { + debug_print("%s", "Rawml structure not initialized\n"); + return T_UNKNOWN; + } + if (rawml->resources == NULL) { + debug_print("%s", "Rawml structure not initialized\n"); + return T_UNKNOWN; + } + MOBIPart *curr = rawml->resources; + while (curr != NULL) { + if (curr->uid == uid) { + return curr->type; + } + curr = curr->next; + } + return T_UNKNOWN; +} + +/** + @brief Get palm database record with given sequential number (first record has number 0) + + @param[in] m MOBIData structure with loaded data + @param[in] num Sequential number + @return Pointer to MOBIPdbRecord record structure, NULL on failure + */ +MOBIPdbRecord * mobi_get_record_by_seqnumber(const MOBIData *m, const size_t num) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + if (m->rec == NULL) { + return NULL; + } + MOBIPdbRecord *curr = m->rec; + size_t i = 0; + while (curr != NULL) { + if (i++ == num) { + return curr; + } + curr = curr->next; + } + return NULL; +} + +/** + @brief Get palm database record with data header starting with given 4-byte magic string + + @param[in] m MOBIData structure with loaded data + @param[in] magic Magic header + @return Pointer to MOBIPdbRecord record structure, NULL if not found or on failure + */ +MOBIPdbRecord * mobi_get_record_by_magic(const MOBIData *m, const unsigned char magic[4]) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + + MOBIPdbRecord *curr = m->rec; + while (curr != NULL) { + if (curr->size >= 4 && memcmp(curr->data, magic, 4) != 0) { + return curr; + } + curr = curr->next; + } + return NULL; +} + + +/** + @brief Extract palm count database records starting with given sequential number from MOBIData structure + + Extracted records are removed from palm database. + Number of extracted records may be less then given count, if there are not enough records in database. + + @param[in,out] m MOBIData structure with loaded data + @param[in] num Sequential number + @param[in,out] count Records count, updated with number of records effectively extracted + @return Pointer to MOBIPdbRecord record structure, NULL if not found or on failure + */ +MOBIPdbRecord * mobi_extract_records_by_seqnumber(MOBIData *m, const size_t num, size_t *count) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + + MOBIPdbRecord *root = NULL; + MOBIPdbRecord *prev = NULL; + MOBIPdbRecord *curr = NULL; + if (num > 0) { + root = mobi_get_record_by_seqnumber(m, num - 1); + if (root) { + curr = root->next; + } + } else { + curr = m->rec; + } + + MOBIPdbRecord *extracted = curr; + + size_t i = 0; + while (curr != NULL && i < *count) { + i++; + prev = curr; + curr = curr->next; + } + + if (prev == NULL) { + return NULL; + } + + if (root == NULL) { + m->rec = prev->next; + } else { + root->next = prev->next; + } + prev->next = NULL; + + *count = i; + if (m->ph->rec_count >= i) { + m->ph->rec_count -= i; + } else { + debug_print("%s\n", "Real record count differs from header value"); + m->ph->rec_count = 0; + } + + debug_print("Extracted %zu records starting with index = %zu\n", *count, num); + + return extracted; +} + + +/** + @brief Insert palm database records at given sequential number + + @param[in,out] m MOBIData structure with loaded data + @param[in,out] record Linked list of records + @param[in] num Sequential number + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_insert_records_by_seqnumber(MOBIData *m, MOBIPdbRecord *record, const size_t num) { + if (m == NULL || m->rec == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (record == NULL) { + return MOBI_SUCCESS; + } + + MOBIPdbRecord *curr = record; + size_t count = 1; + while (curr->next != NULL) { + curr = curr->next; + count++; + } + + if (m->ph->rec_count + count > UINT16_MAX) { + debug_print("%s", "Number of records beyond database limit\n"); + return MOBI_DATA_CORRUPT; + } + + MOBIPdbRecord *next = NULL; + if (num == 0) { + next = m->rec; + m->rec = record; + } else { + MOBIPdbRecord *prev = mobi_get_record_by_seqnumber(m, num - 1); + if (prev == NULL) { + debug_print("%s", "Insert point not found\n"); + return MOBI_DATA_CORRUPT; + } + next = prev->next; + prev->next = record; + } + curr->next = next; + m->ph->rec_count += count; + + debug_print("Inserted %zu records at index = %zu\n", count, num); + + return MOBI_SUCCESS; +} + +/** + @brief Delete palm count database records starting with given sequential number from MOBIData structure + + Number of deleted records may be less then given count, if there are not enough records in database. + + @param[in,out] m MOBIData structure with loaded data + @param[in] num Sequential number + @param[in,out] count Records count, updated wth number of records effectively extracted + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_delete_records_by_seqnumber(MOBIData *m, const size_t num, size_t *count) { + + // extract records + MOBIPdbRecord *curr = mobi_extract_records_by_seqnumber(m, num, count); + + // delete them + while (curr != NULL) { + MOBIPdbRecord *tmp = curr; + curr = curr->next; + free(tmp->data); + free(tmp); + tmp = NULL; + } + + debug_print("Deleted %zu records starting with index = %zu\n", *count, num); + + return MOBI_SUCCESS; +} + +/** + @brief Delete palm database record with given sequential number from MOBIData structure + + @param[in,out] m MOBIData structure with loaded data + @param[in] num Sequential number + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_delete_record_by_seqnumber(MOBIData *m, const size_t num) { + size_t count = 1; + return mobi_delete_records_by_seqnumber(m, num, &count); +} + +/** + @brief Get EXTH record with given MOBIExthTag tag + + @param[in] m MOBIData structure with loaded data + @param[in] tag MOBIExthTag EXTH record tag + @return Pointer to MOBIExthHeader record structure + */ +MOBIExthHeader * mobi_get_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag) { + debug_print("Loading EXTH record with tag %i\n", tag); + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + if (m->eh == NULL) { + return NULL; + } + MOBIExthHeader *curr = m->eh; + while (curr != NULL) { + if (curr->tag == tag) { + return curr; + } + curr = curr->next; + } + return NULL; +} + +/** + @brief Get EXTH record with given MOBIExthTag tag. Start list search at given record. + + If start_tag is NULL search will start from the root of the linked list. + After successfull search start will be set to next record in the list. + + @param[in] m MOBIData structure with loaded data + @param[in] tag MOBIExthTag EXTH record tag + @param[in,out] start MOBIExthHeader EXTH record to begin search with + @return Pointer to MOBIExthHeader record structure + */ +MOBIExthHeader * mobi_next_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag, MOBIExthHeader **start) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return NULL; + } + if (m->eh == NULL) { + return NULL; + } + MOBIExthHeader *curr; + if (*start) { + curr = *start; + *start = NULL; + } else { + curr = m->eh; + } + while (curr != NULL) { + if (curr->tag == tag) { + *start = curr->next; + return curr; + } + curr = curr->next; + } + return NULL; +} + +/** + @brief Add new EXTH record with given tag and value. + + @param[in,out] m MOBIData structure with loaded data + @param[in] tag MOBIExthTag EXTH record tag + @param[in] size Value size + @param[in] value Value + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_add_exthrecord(MOBIData *m, const MOBIExthTag tag, const uint32_t size, const void *value) { + if (size == 0) { + debug_print("%s\n", "Record size is zero"); + return MOBI_PARAM_ERR; + } + size_t count = 2; + while (m && count--) { + if (m->mh == NULL) { + debug_print("%s\n", "Mobi header must be initialized"); + return MOBI_INIT_FAILED; + } + MOBIExthMeta meta = mobi_get_exthtagmeta_by_tag(tag); + MOBIExthHeader *record = calloc(1, sizeof(MOBIExthHeader)); + if (record == NULL) { + debug_print("%s\n", "Memory allocation for EXTH record failed"); + return MOBI_MALLOC_FAILED; + } + record->tag = tag; + record->size = size; + record->data = malloc(size); + if (record->data == NULL) { + debug_print("%s\n", "Memory allocation for EXTH data failed"); + free(record); + return MOBI_MALLOC_FAILED; + } + if (meta.type == EXTH_STRING && mobi_is_cp1252(m)) { + debug_print("%s\n", "Adding CP1252 string data"); + char *data = malloc(size + 1); + if (data == NULL) { + free(record->data); + free(record); + return MOBI_MALLOC_FAILED; + } + size_t data_size = size + 1; + MOBI_RET ret = mobi_utf8_to_cp1252(data, value, &data_size, size); + if (ret != MOBI_SUCCESS) { + free(record->data); + free(record); + free(data); + return ret; + } + memcpy(record->data, data, data_size); + record->size = (uint32_t) data_size; + free(data); + } else if (meta.name && meta.type == EXTH_NUMERIC && size == sizeof(uint32_t)) { + debug_print("%s\n", "Adding numeric data"); + MOBIBuffer *buf = mobi_buffer_init_null(record->data, size); + if (buf == NULL) { + free(record->data); + free(record); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_add32(buf, *(uint32_t *) value); + mobi_buffer_free_null(buf); + } else { + debug_print("%s\n", "Adding raw data"); + memcpy(record->data, value, size); + } + debug_print("Added record %u (%u bytes)\n", meta.tag, size); + + record->next = NULL; + if (m->eh == NULL) { + if (m->mh->exth_flags == NULL) { + m->mh->exth_flags = malloc(sizeof(uint32_t)); + if (m->mh->exth_flags == NULL) { + debug_print("%s\n", "Memory allocation failed"); + free(record->data); + free(record); + return MOBI_MALLOC_FAILED; + } + } + *m->mh->exth_flags = 0x40; + m->eh = record; + } else { + MOBIExthHeader *curr = m->eh; + while(curr->next) { + curr = curr->next; + } + curr->next = record; + } + m = m->next; + } + return MOBI_SUCCESS; +} + +/** + @brief Delete EXTH record. + + @param[in,out] m MOBIData structure with loaded data + @param[in] record Record to be deleted + @return Pointer to next record in the linked list (NULL if none) + */ +MOBIExthHeader * mobi_delete_exthrecord(MOBIData *m, MOBIExthHeader *record) { + if (record == NULL || m == NULL || m->eh == NULL) { + return NULL; + } + MOBIExthHeader *next = record->next; + if (next) { + /* not last */ + MOBIExthHeader *curr = m->eh; + if (curr == record) { + /* first */ + m->eh = next; + } else { + /* not first */ + while (curr) { + if (curr->next == record) { + curr->next = next; + break; + } + curr = curr->next; + } + } + free(record->data); + free(record); + } else if (m->eh == record) { + /* last && first */ + free(m->eh->data); + free(m->eh); + m->eh = NULL; + } else { + /* last */ + MOBIExthHeader *curr = m->eh; + while (curr) { + if (curr->next == record) { + curr->next = NULL; + break; + } + curr = curr->next; + } + free(record->data); + free(record); + } + return next; +} + +/** + @brief Delete all EXTH records with given MOBIExthTag tag + + @param[in,out] m MOBIData structure with loaded data + @param[in] tag MOBIExthTag EXTH record tag + @return Pointer to MOBIExthHeader record structure + */ +MOBI_RET mobi_delete_exthrecord_by_tag(MOBIData *m, const MOBIExthTag tag) { + size_t count = 2; + while (m && count--) { + if (m->eh == NULL) { + debug_print("%s", "No exth records\n"); + return MOBI_SUCCESS; + } + MOBIExthHeader *curr = m->eh; + while (curr) { + if (curr->tag == tag) { + curr = mobi_delete_exthrecord(m, curr); + } else { + curr = curr->next; + } + } + m = m->next; + } + return MOBI_SUCCESS; +} + +/** + @brief Array of known EXTH tags. + Name strings shamelessly copied from KindleUnpack + */ +const MOBIExthMeta mobi_exth_tags[] = { + /* numeric */ + {EXTH_SAMPLE, EXTH_NUMERIC, "Sample"}, + {EXTH_STARTREADING, EXTH_NUMERIC, "Start offset"}, + {EXTH_KF8BOUNDARY, EXTH_NUMERIC, "K8 boundary offset"}, + {EXTH_COUNTRESOURCES, EXTH_NUMERIC, "K8 count of resources, fonts, images"}, + {EXTH_RESCOFFSET, EXTH_NUMERIC, "RESC offset"}, + {EXTH_COVEROFFSET, EXTH_NUMERIC, "Cover offset"}, + {EXTH_THUMBOFFSET, EXTH_NUMERIC, "Thumbnail offset"}, + {EXTH_HASFAKECOVER, EXTH_NUMERIC, "Has fake cover"}, + {EXTH_CREATORSOFT, EXTH_NUMERIC, "Creator software"}, + {EXTH_CREATORMAJOR, EXTH_NUMERIC, "Creator major version"}, + {EXTH_CREATORMINOR, EXTH_NUMERIC, "Creator minor version"}, + {EXTH_CREATORBUILD, EXTH_NUMERIC, "Creator build number"}, + {EXTH_CLIPPINGLIMIT, EXTH_NUMERIC, "Clipping limit"}, + {EXTH_PUBLISHERLIMIT, EXTH_NUMERIC, "Publisher limit"}, + {EXTH_TTSDISABLE, EXTH_NUMERIC, "Text to speech disabled"}, + {EXTH_READFORFREE, EXTH_NUMERIC, "Read for Free"}, + /* strings */ + {EXTH_DRMSERVER, EXTH_STRING, "Drm server id"}, + {EXTH_DRMCOMMERCE, EXTH_STRING, "Drm commerce id"}, + {EXTH_DRMEBOOKBASE, EXTH_STRING, "Drm Ebookbase book id"}, + {EXTH_TITLE, EXTH_STRING, "Title"}, + {EXTH_AUTHOR, EXTH_STRING, "Creator"}, + {EXTH_PUBLISHER, EXTH_STRING, "Publisher"}, + {EXTH_IMPRINT, EXTH_STRING, "Imprint"}, + {EXTH_DESCRIPTION, EXTH_STRING, "Description"}, + {EXTH_ISBN, EXTH_STRING, "ISBN"}, + {EXTH_SUBJECT, EXTH_STRING, "Subject"}, + {EXTH_PUBLISHINGDATE, EXTH_STRING, "Published"}, + {EXTH_REVIEW, EXTH_STRING, "Review"}, + {EXTH_CONTRIBUTOR, EXTH_STRING, "Contributor"}, + {EXTH_RIGHTS, EXTH_STRING, "Rights"}, + {EXTH_SUBJECTCODE, EXTH_STRING, "Subject code"}, + {EXTH_TYPE, EXTH_STRING, "Type"}, + {EXTH_SOURCE, EXTH_STRING, "Source"}, + {EXTH_ASIN, EXTH_STRING, "ASIN"}, + {EXTH_VERSION, EXTH_STRING, "Version number"}, + {EXTH_ADULT, EXTH_STRING, "Adult"}, + {EXTH_PRICE, EXTH_STRING, "Price"}, + {EXTH_CURRENCY, EXTH_STRING, "Currency"}, + {EXTH_FIXEDLAYOUT, EXTH_STRING, "Fixed layout"}, + {EXTH_BOOKTYPE, EXTH_STRING, "Book type"}, + {EXTH_ORIENTATIONLOCK, EXTH_STRING, "Orientation lock"}, + {EXTH_ORIGRESOLUTION, EXTH_STRING, "Original resolution"}, + {EXTH_ZEROGUTTER, EXTH_STRING, "Zero gutter"}, + {EXTH_ZEROMARGIN, EXTH_STRING, "Zero margin"}, + {EXTH_KF8COVERURI, EXTH_STRING, "K8 masthead/cover image"}, + {EXTH_REGIONMAGNI, EXTH_STRING, "Region magnification"}, + {EXTH_DICTNAME, EXTH_STRING, "Dictionary short name"}, + {EXTH_WATERMARK, EXTH_STRING, "Watermark"}, + {EXTH_DOCTYPE, EXTH_STRING, "Document type"}, + {EXTH_LASTUPDATE, EXTH_STRING, "Last update time"}, + {EXTH_UPDATEDTITLE, EXTH_STRING, "Updated title"}, + {EXTH_ASIN504, EXTH_STRING, "ASIN (504)"}, + {EXTH_TITLEFILEAS, EXTH_STRING, "Title file as"}, + {EXTH_CREATORFILEAS, EXTH_STRING, "Creator file as"}, + {EXTH_PUBLISHERFILEAS, EXTH_STRING, "Publisher file as"}, + {EXTH_LANGUAGE, EXTH_STRING, "Language"}, + {EXTH_ALIGNMENT, EXTH_STRING, "Primary writing mode"}, + {EXTH_PAGEDIR, EXTH_STRING, "Page progression direction"}, + {EXTH_OVERRIDEFONTS, EXTH_STRING, "Override kindle fonts"}, + {EXTH_SORCEDESC, EXTH_STRING, "Original source description"}, + {EXTH_DICTLANGIN, EXTH_STRING, "Dictionary input language"}, + {EXTH_DICTLANGOUT, EXTH_STRING, "Dictionary output language"}, + {EXTH_INPUTSOURCE, EXTH_STRING, "Input source type"}, + {EXTH_CREATORBUILDREV, EXTH_STRING, "Creator build revision"}, + {EXTH_CREATORSTRING, EXTH_STRING, "Creator software string"}, + /* binary */ + {EXTH_TAMPERKEYS, EXTH_BINARY, "Tamper proof keys"}, + {EXTH_FONTSIGNATURE, EXTH_BINARY, "Font signature"}, + {EXTH_RENTAL, EXTH_BINARY, "Rental indicator"}, // uint64_t + {EXTH_UNK403, EXTH_BINARY, "Unknown (403)"}, + {EXTH_UNK407, EXTH_BINARY, "Unknown (407)"}, + {EXTH_UNK450, EXTH_BINARY, "Unknown (450)"}, + {EXTH_UNK451, EXTH_BINARY, "Unknown (451)"}, + {EXTH_UNK452, EXTH_BINARY, "Unknown (452)"}, + {EXTH_UNK453, EXTH_BINARY, "Unknown (453)"}, + /* end */ + {0, 0, NULL}, +}; + +/** + @brief Get MOBIExthMeta tag structure by MOBIExthTag tag id + + @param[in] tag Tag id + @return MOBIExthMeta structure for given tag id, zeroed structure on failure + */ +MOBIExthMeta mobi_get_exthtagmeta_by_tag(const MOBIExthTag tag) { + size_t i = 0; + while (mobi_exth_tags[i].tag > 0) { + if (mobi_exth_tags[i].tag == tag) { + return mobi_exth_tags[i]; + } + i++; + } + return (MOBIExthMeta) {0, 0, NULL}; +} + +/** + @brief Decode big-endian value stored in EXTH record + + Only for EXTH records storing numeric values + + @param[in] data Memory area storing EXTH record data + @param[in] size Size of EXTH record data + @return 32-bit value + */ +uint32_t mobi_decode_exthvalue(const unsigned char *data, const size_t size) { + /* FIXME: EXTH numeric data is max 32-bit? */ + uint32_t val = 0; + size_t i = min(size, 4); + while (i--) { + val |= (uint32_t) *data++ << (i * 8); + } + return val; +} + +#define MOBI_UTF8_MAXBYTES 4 +/** + @brief Html entity mapping to utf-8 sequence + */ +typedef struct { + const char *name; /**< Html entity name */ + const char utf8_bytes[MOBI_UTF8_MAXBYTES + 1]; /**< Utf-8 sequence */ +} HTMLEntity; + +/** + @brief Basic named html entities mapping to utf-8 sequences + */ +const HTMLEntity entities[] = { + { """, "\"" }, + { "&", "&" }, + { "<", "<" }, + { ">", ">" }, + { "'", "'" }, + { " ", "\xc2\xa0" }, + { "©", "\xc2\xa9" }, + { "®", "\xc2\xae" }, + { "¢", "\xc2\xa2" }, + { "£", "\xc2\xa3" }, + { "§", "\xc2\xa7" }, + { "«", "\xc2\xab" }, + { "»", "\xc2\xbb" }, + { "°", "\xc2\xb0" }, + { "±", "\xc2\xb1" }, + { "·", "\xc2\xb7" }, + { "½", "\xc2\xbd" }, + { "–", "\xe2\x80\x93" }, + { "—", "\xe2\x80\x94" }, + { "‘", "\xe2\x80\x98" }, + { "‚", "\xe2\x80\x9a" }, + { "“", "\xe2\x80\x9c" }, + { "”", "\xe2\x80\x9d" }, + { "„", "\xe2\x80\x9e" }, + { "†", "\xe2\x80\xa0" }, + { "‡", "\xe2\x80\xa1" }, + { "•", "\xe2\x80\xa2" }, + { "…", "\xe2\x80\xa6" }, + { "′", "\xe2\x80\xb2" }, + { "″", "\xe2\x80\xb3" }, + { "€", "\xe2\x82\xac" }, + { "™", "\xe2\x84\xa2" } +}; + +/** + @brief Convert html entities in string to utf-8 characters + + @param[in] input Input string + @return Converted string + */ +char * mobi_decode_htmlentities(const char *input) { + if (!input) { + return NULL; + } + const size_t codepoint_max = 0x10ffff; + size_t output_length = strlen(input) + 1; + char *in = (char *) input; + /* output size will be less or equal to input */ + char *output = malloc(output_length); + char *out = output; + if (output == NULL) { + debug_print("Memory allocation failed (%zu bytes)\n", output_length); + return NULL; + } + char *offset = in; + while ((in = strchr(in, '&'))) { + size_t decoded_length = 0; + char *end = NULL; + char decoded[MOBI_UTF8_MAXBYTES + 1] = { 0 }; + if (in[1] == '#' && (in[2] == 'x' || in[2] == 'X')) { + // hex entity + size_t codepoint = strtoul(in + 3, &end, 16); + if (*end++ == ';' && codepoint <= codepoint_max) { + decoded_length = mobi_unicode_to_utf8(decoded, codepoint); + } + } else if (in[1] == '#') { + // dec entity + size_t codepoint = strtoul(in + 2, &end, 10); + if (*end++ == ';' && codepoint <= codepoint_max) { + decoded_length = mobi_unicode_to_utf8(decoded, codepoint); + } + } else { + // named entity + for (size_t i = 0; i < ARRAYSIZE(entities); i++) { + if (strncmp(in, entities[i].name, strlen(entities[i].name)) == 0) { + int ret = snprintf(decoded, MOBI_UTF8_MAXBYTES + 1, "%s", entities[i].utf8_bytes); + if (ret > 0) { + decoded_length = (size_t) ret; + end = in + strlen(entities[i].name); + break; + } + } + } + } + if (decoded_length) { + size_t len = (size_t) (in - offset); + memcpy(out, offset, len); + offset = end; + out += len; + memcpy(out, decoded, decoded_length); + out += decoded_length; + } + in += decoded_length + 1; + } + strcpy(out, offset); + return output; +} + +/** + @brief Decode string stored in EXTH record + + Only for EXTH records storing string values + + @param[in] m MOBIData structure loaded with MOBI data + @param[in] data Memory area storing EXTH record data + @param[in] size Size of EXTH record data + @return String from EXTH record in utf-8 encoding + */ +char * mobi_decode_exthstring(const MOBIData *m, const unsigned char *data, const size_t size) { + if (!m || !data) { + return NULL; + } + size_t out_length = 3 * size + 1; + size_t in_length = size; + char *exth_string = malloc(out_length); + if (exth_string == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return NULL; + } + if (mobi_is_cp1252(m)) { + MOBI_RET ret = mobi_cp1252_to_utf8(exth_string, (const char *) data, &out_length, in_length); + if (ret != MOBI_SUCCESS) { + free(exth_string); + return NULL; + } + } else { + memcpy(exth_string, data, size); + out_length = size; + } + exth_string[out_length] = '\0'; + char *exth_decoded = mobi_decode_htmlentities(exth_string); + if (exth_decoded != NULL) { + free(exth_string); + return exth_decoded; + } + return exth_string; +} + +/** + @brief Swap endianness of 32-bit value + + @param[in] val 4-byte unsigned integer + @return Integer with swapped endianness + */ +uint32_t mobi_swap32(const uint32_t val) { + return ((((val) >> 24) & 0x000000ff) | + (((val) >> 8) & 0x0000ff00) | + (((val) << 8) & 0x00ff0000) | + (((val) << 24) & 0xff000000)); + +} + +/** + @brief Convert time values from palmdoc header to time tm struct + + Older files set time in mac format. Newer ones in unix time. + + @param[in] pdb_time Time value from PDB header + @return Time structure struct tm of time.h + */ +struct tm * mobi_pdbtime_to_time(const long pdb_time) { + time_t time = pdb_time; + const int unix1996 = 820454400; + if (time < unix1996 && time > 0) { + /* sometimes dates are stored as little endian */ + time = mobi_swap32((uint32_t) time); + } + const uint32_t mactime_flag = (uint32_t) (1U << 31); + if (time & mactime_flag) { + debug_print("%s\n", "mac time"); + time -= EPOCH_MAC_DIFF; + } + return localtime(&time); +} + +/** + @brief Lookup table for number of bits set in a single byte + */ +static const char setbits[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +/** + @brief Get number of bits set in a given byte + + @param[in] byte A byte + @return Number of bits set + */ +int mobi_bitcount(const uint8_t byte) { + return setbits[byte]; +} + +/** + @brief Decompress text record (internal). + + Internal function for mobi_get_rawml and mobi_dump_rawml. + Decompressed output is stored either in a file or in a text string + + @param[in] m MOBIData structure loaded with MOBI data + @param[in,out] text Memory area to be filled with decompressed output + @param[in,out] file If not NULL output is written to the file, otherwise to text string + @param[in,out] len Length of the memory allocated for the text string, on return set to decompressed text length + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_decompress_content(const MOBIData *m, char *text, FILE *file, size_t *len) { + int dump = false; + if (file != NULL) { + dump = true; + } + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (mobi_is_encrypted(m) && !mobi_has_drmkey(m)) { + debug_print("%s", "Document is encrypted\n"); + return MOBI_FILE_ENCRYPTED; + } + const size_t offset = mobi_get_kf8offset(m); + if (m->rh == NULL || m->rh->text_record_count == 0) { + debug_print("%s", "Text records not found in MOBI header\n"); + return MOBI_DATA_CORRUPT; + } + const size_t text_rec_index = 1 + offset; + size_t text_rec_count = m->rh->text_record_count; + const uint16_t compression_type = m->rh->compression_type; + /* check for extra data at the end of text files */ + uint16_t extra_flags = 0; + if (m->mh && m->mh->extra_flags) { + extra_flags = *m->mh->extra_flags; + } + /* get first text record */ + const MOBIPdbRecord *curr = mobi_get_record_by_seqnumber(m, text_rec_index); + MOBIHuffCdic *huffcdic = NULL; + if (compression_type == MOBI_COMPRESSION_HUFFCDIC) { + /* load huff/cdic tables */ + huffcdic = mobi_init_huffcdic(); + if (huffcdic == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = mobi_parse_huffdic(m, huffcdic); + if (ret != MOBI_SUCCESS) { + mobi_free_huffcdic(huffcdic); + return ret; + } + } + /* get following CDIC records */ + size_t text_length = 0; + while (text_rec_count-- && curr) { + size_t extra_size = 0; + if (extra_flags) { + extra_size = mobi_get_record_extrasize(curr, extra_flags); + if (extra_size == MOBI_NOTSET) { + mobi_free_huffcdic(huffcdic); + return MOBI_DATA_CORRUPT; + } + } + size_t decompressed_size = mobi_get_textrecord_maxsize(m); + unsigned char *decompressed = malloc(decompressed_size); + if (decompressed == NULL) { + mobi_free_huffcdic(huffcdic); + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + MOBI_RET ret = MOBI_SUCCESS; +#ifdef USE_ENCRYPTION + if (mobi_is_encrypted(m) && mobi_has_drmkey(m)) { + if (compression_type != MOBI_COMPRESSION_HUFFCDIC) { + /* decrypt also multibyte extra data */ + extra_size = mobi_get_record_extrasize(curr, extra_flags & 0xfffe); + } + if (extra_size == MOBI_NOTSET || extra_size > curr->size) { + mobi_free_huffcdic(huffcdic); + free(decompressed); + return MOBI_DATA_CORRUPT; + } + const size_t decrypt_size = curr->size - extra_size; + if (decrypt_size > decompressed_size) { + if (decrypt_size <= curr->size) { + unsigned char *tmp = realloc(decompressed, decrypt_size); + if (tmp == NULL) { + debug_print("%s\n", "Memory allocation failed"); + mobi_free_huffcdic(huffcdic); + free(decompressed); + return MOBI_MALLOC_FAILED; + } + decompressed = tmp; + } else { + debug_print("Record too large: %zu\n", decrypt_size); + mobi_free_huffcdic(huffcdic); + free(decompressed); + return MOBI_DATA_CORRUPT; + } + } + if (decrypt_size) { + ret = mobi_buffer_decrypt(decompressed, curr->data, decrypt_size, m); + if (ret != MOBI_SUCCESS) { + mobi_free_huffcdic(huffcdic); + free(decompressed); + return ret; + } + memcpy(curr->data, decompressed, decrypt_size); + } + if (compression_type != MOBI_COMPRESSION_HUFFCDIC && (extra_flags & 1)) { + // update multibyte data size after decryption + extra_size = mobi_get_record_extrasize(curr, extra_flags); + if (extra_size == MOBI_NOTSET) { + free(decompressed); + return MOBI_DATA_CORRUPT; + } + } + } +#endif + if (extra_size > curr->size) { + debug_print("Wrong record size: -%zu\n", extra_size - curr->size); + mobi_free_huffcdic(huffcdic); + free(decompressed); + return MOBI_DATA_CORRUPT; + } + if (extra_size == curr->size) { + debug_print("Skipping empty record%s", "\n"); + free(decompressed); + curr = curr->next; + continue; + } + const size_t record_size = curr->size - extra_size; + switch (compression_type) { + case MOBI_COMPRESSION_NONE: + /* no compression */ + if (record_size > decompressed_size) { + debug_print("Record too large: %zu\n", record_size); + free(decompressed); + return MOBI_DATA_CORRUPT; + } + memcpy(decompressed, curr->data, record_size); + decompressed_size = record_size; + if (mobi_exists_mobiheader(m) && mobi_get_fileversion(m) <= 3) { + /* workaround for some old files with null characters inside record */ + mobi_remove_zeros(decompressed, &decompressed_size); + } + break; + case MOBI_COMPRESSION_PALMDOC: + /* palmdoc lz77 compression */ + ret = mobi_decompress_lz77(decompressed, curr->data, &decompressed_size, record_size); + if (ret != MOBI_SUCCESS) { + free(decompressed); + return ret; + } + break; + case MOBI_COMPRESSION_HUFFCDIC: + /* mobi huffman compression */ + ret = mobi_decompress_huffman(decompressed, curr->data, &decompressed_size, record_size, huffcdic); + if (ret != MOBI_SUCCESS) { + free(decompressed); + mobi_free_huffcdic(huffcdic); + return ret; + } + break; + default: + debug_print("%s", "Unknown compression type\n"); + mobi_free_huffcdic(huffcdic); + free(decompressed); + return MOBI_DATA_CORRUPT; + } + curr = curr->next; + if (dump) { + fwrite(decompressed, 1, decompressed_size, file); + } else { + if (text_length + decompressed_size > *len) { + debug_print("%s", "Text buffer too small\n"); + /* free huff/cdic tables */ + mobi_free_huffcdic(huffcdic); + free(decompressed); + return MOBI_PARAM_ERR; + } + memcpy(text + text_length, decompressed, decompressed_size); + text_length += decompressed_size; + text[text_length] = '\0'; + } + free(decompressed); + } + /* free huff/cdic tables */ + mobi_free_huffcdic(huffcdic); + if (len) { + *len = text_length; + } + return MOBI_SUCCESS; +} + +/** + @brief Decompress text to a text buffer. + + @param[in] m MOBIData structure loaded with MOBI data + @param[in,out] text Memory area to be filled with decompressed output + @param[in,out] len Length of the memory allocated for the text string, on return will be set to decompressed text length + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_rawml(const MOBIData *m, char *text, size_t *len) { + if (text == NULL || len == NULL) { + debug_print("%s", "Parameter error: text or len is NULL\n"); + return MOBI_PARAM_ERR; + } + if (m->rh->text_length > *len) { + debug_print("%s", "Text buffer smaller then text size declared in record0 header\n"); + return MOBI_PARAM_ERR; + } + text[0] = '\0'; + return mobi_decompress_content(m, text, NULL, len); +} + +/** + @brief Decompress text record to an open file descriptor. + + Internal function for mobi_get_rawml and mobi_dump_rawml. + Decompressed output is stored either in a file or in a text string + + @param[in] m MOBIData structure loaded with MOBI data + @param[in,out] file File descriptor + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_dump_rawml(const MOBIData *m, FILE *file) { + if (file == NULL) { + debug_print("%s", "File descriptor is NULL\n"); + return MOBI_FILE_NOT_FOUND; + } + return mobi_decompress_content(m, NULL, file, NULL); +} + +/** + @brief Check if MOBI header is loaded / present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_mobiheader(const MOBIData *m) { + if (m == NULL || m->mh == NULL) { + return false; + } + return true; +} + +/** + @brief Check if skeleton INDX is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_skel_indx(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return false; + } + if (m->mh->skeleton_index == NULL || *m->mh->skeleton_index == MOBI_NOTSET) { + debug_print("%s", "SKEL INDX record not found\n"); + return false; + } + return true; +} + +/** + @brief Check if FDST record is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_fdst(const MOBIData *m) { + if (!mobi_exists_mobiheader(m) || mobi_get_fileversion(m) <= 3) { + return false; + } + if (mobi_get_fileversion(m) >= 8) { + if (m->mh->fdst_index && *m->mh->fdst_index != MOBI_NOTSET) { + return true; + } + } else { + if ((m->mh->fdst_section_count && *m->mh->fdst_section_count > 1) + && (m->mh->last_text_index && *m->mh->last_text_index != (uint16_t) -1)) { + return true; + } + } + debug_print("%s", "FDST record not found\n"); + return false; +} + +/** + @brief Get sequential number of FDST record + + @param[in] m MOBIData structure loaded with MOBI data + @return Record number on success, MOBI_NOTSET otherwise + */ +size_t mobi_get_fdst_record_number(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return MOBI_NOTSET; + } + const size_t offset = mobi_get_kf8offset(m); + if (m->mh->fdst_index && *m->mh->fdst_index != MOBI_NOTSET) { + if (m->mh->fdst_section_count && *m->mh->fdst_section_count > 1) { + return *m->mh->fdst_index + offset; + } + } + if (m->mh->fdst_section_count && *m->mh->fdst_section_count > 1) { + /* FIXME: if KF7, is it safe to asume last_text_index has fdst index */ + if (m->mh->last_text_index) { + return *m->mh->last_text_index; + } + } + return MOBI_NOTSET; +} + +/** + @brief Check if fragments INDX is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_frag_indx(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return false; + } + if (m->mh->fragment_index == NULL || *m->mh->fragment_index == MOBI_NOTSET) { + return false; + } + debug_print("%s", "Fragments INDX found\n"); + return true; +} + +/** + @brief Check if guide INDX is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_guide_indx(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return false; + } + if (m->mh->guide_index == NULL || *m->mh->guide_index == MOBI_NOTSET) { + return false; + } + debug_print("%s", "Guide INDX found\n"); + return true; +} + +/** + @brief Check if ncx INDX is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_ncx(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return false; + } + if (m->mh->ncx_index == NULL || *m->mh->ncx_index == MOBI_NOTSET) { + return false; + } + debug_print("%s", "NCX INDX found\n"); + return true; +} + +/** + @brief Check if orth INDX is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_orth(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return false; + } + if (m->mh->orth_index == NULL || *m->mh->orth_index == MOBI_NOTSET) { + return false; + } + debug_print("%s", "ORTH INDX found\n"); + return true; +} + +/** + @brief Check if infl INDX is present in the loaded file + + @param[in] m MOBIData structure loaded with MOBI data + @return true on success, false otherwise + */ +bool mobi_exists_infl(const MOBIData *m) { + if (!mobi_exists_mobiheader(m)) { + return false; + } + if (m->mh->infl_index == NULL || *m->mh->infl_index == MOBI_NOTSET) { + return false; + } + debug_print("%s", "INFL INDX found\n"); + return true; +} + +/** + @brief Get file type of given part with number [part_number] + + @param[in] rawml MOBIRawml parsed records structure + @param[in] part_number Sequential number of the part within rawml structure + @return MOBIFiletype file type + */ +MOBIFiletype mobi_determine_flowpart_type(const MOBIRawml *rawml, const size_t part_number) { + if (part_number == 0 || mobi_is_rawml_kf8(rawml) == false) { + return T_HTML; + } + if (part_number > 9999) { + debug_print("Corrupt part number: %zu\n", part_number); + return T_UNKNOWN; + } + char target[30]; + snprintf(target, 30, "\"kindle:flow:%04zu?mime=", part_number); + unsigned char *data_start = rawml->flow->data; + unsigned char *data_end = data_start + rawml->flow->size - 1; + MOBIResult result; + MOBI_RET ret = mobi_find_attrvalue(&result, data_start, data_end, T_HTML, target); + if (ret == MOBI_SUCCESS && result.start) { + if (strstr(result.value, "text/css")) { + return T_CSS; + } + if (strstr(result.value, "image/svg+xml")) { + return T_SVG; + } + } + return T_UNKNOWN; +} + +/** + @brief Get font type of given font resource + + @param[in] font_data Font resource data + @param[in] font_size Font resource size + @return MOBIFiletype file type + */ +MOBIFiletype mobi_determine_font_type(const unsigned char *font_data, const size_t font_size) { + const char otf_magic[] = "OTTO"; + const char ttf_magic[] = "\0\1\0\0"; + const char ttf2_magic[] = "true"; + + if (font_size >= 4) { + if (memcmp(font_data, otf_magic, 4) == 0) { + return T_OTF; + } + if (memcmp(font_data, ttf_magic, 4) == 0) { + return T_TTF; + } + if (memcmp(font_data, ttf2_magic, 4) == 0) { + return T_TTF; + } + } + debug_print("Unknown font resource type%s", "\n"); + return T_UNKNOWN; +} + +/** + @brief Replace part data with decoded audio data + + @param[in,out] part MOBIPart structure containing font resource, decoded part type will be set in the structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_add_audio_resource(MOBIPart *part) { + unsigned char *data = NULL; + size_t size = 0; + MOBI_RET ret = mobi_decode_audio_resource(&data, &size, part); + if (ret != MOBI_SUCCESS) { + return ret; + } + part->data = data; + part->size = size; + /* FIXME: the only possible audio type is mp3 */ + part->type = T_MP3; + + return MOBI_SUCCESS; +} + +/** + @brief Decode audio resource + + @param[in,out] decoded_resource Pointer to data offset in mobipocket record. + @param[in,out] decoded_size Decoded resource data size + @param[in,out] part MOBIPart structure containing resource, decoded part type will be set in the structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decode_audio_resource(unsigned char **decoded_resource, size_t *decoded_size, MOBIPart *part) { + if (part->size < MEDIA_HEADER_LEN) { + debug_print("Audio resource record too short (%zu)\n", part->size); + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init_null(part->data, part->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char magic[5]; + mobi_buffer_getstring(magic, buf, 4); + if (strncmp(magic, AUDI_MAGIC, 4) != 0) { + debug_print("Wrong magic for audio resource: %s\n", magic); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + uint32_t offset = mobi_buffer_get32(buf); + mobi_buffer_setpos(buf, offset); + *decoded_size = buf->maxlen - buf->offset; + *decoded_resource = mobi_buffer_getpointer(buf, *decoded_size); + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Replace part data with decoded video data + + @param[in,out] part MOBIPart structure containing font resource, decoded part type will be set in the structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_add_video_resource(MOBIPart *part) { + unsigned char *data = NULL; + size_t size = 0; + MOBI_RET ret = mobi_decode_video_resource(&data, &size, part); + if (ret != MOBI_SUCCESS) { + return ret; + } + part->data = data; + part->size = size; + part->type = T_MPG; /* FIXME: other types? */ + + return MOBI_SUCCESS; +} + +/** + @brief Decode video resource + + @param[in,out] decoded_resource Pointer to data offset in mobipocket record. + @param[in,out] decoded_size Decoded resource data size + @param[in,out] part MOBIPart structure containing resource, decoded part type will be set in the structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decode_video_resource(unsigned char **decoded_resource, size_t *decoded_size, MOBIPart *part) { + if (part->size < MEDIA_HEADER_LEN) { + debug_print("Video resource record too short (%zu)\n", part->size); + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init_null(part->data, part->size); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + char magic[5]; + mobi_buffer_getstring(magic, buf, 4); + if (strncmp(magic, VIDE_MAGIC, 4) != 0) { + debug_print("Wrong magic for video resource: %s\n", magic); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + uint32_t offset = mobi_buffer_get32(buf); + /* offset is always(?) 12, next four bytes are unknown */ + mobi_buffer_setpos(buf, offset); + *decoded_size = buf->maxlen - buf->offset; + *decoded_resource = mobi_buffer_getpointer(buf, *decoded_size); + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Get embedded source archive + + Some mobi creator software store original conversion source as a zip archive. + The function may return MOBI_SUCCESS even if the data was not found, + so it is neccessary to check whether returned data pointer is not NULL. + + @param[in,out] data Pointer to data offset in pdb record. + @param[in,out] size Pointer to data size + @param[in] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_embedded_source(unsigned char **data, size_t *size, const MOBIData *m) { + *data = NULL; + *size = 0; + if (m == NULL) { + return MOBI_INIT_FAILED; + } + MOBIMobiHeader *header = m->mh; + if (mobi_is_hybrid(m) && m->use_kf8 && m->next) { + /* SRCS index is in KF7 header */ + header = m->next->mh; + } + if (header == NULL || header->srcs_index == NULL || header->srcs_count == NULL || + *header->srcs_index == MOBI_NOTSET || *header->srcs_count == 0) { + return MOBI_SUCCESS; + } + uint32_t index = *header->srcs_index; + + const MOBIPdbRecord *srcs_record = mobi_get_record_by_seqnumber(m, index); + if (srcs_record == NULL) { + return MOBI_SUCCESS; + } + const size_t archive_offset = 16; + + if (srcs_record->size <= archive_offset) { + debug_print("Wrong size of SRCS resource: %zu\n", srcs_record->size); + return MOBI_DATA_CORRUPT; + } + + if (memcmp(srcs_record->data, SRCS_MAGIC, 4) != 0) { + debug_print("Wrong magic for SRCS resource: %c%c%c%c\n", + srcs_record->data[0], srcs_record->data[1], srcs_record->data[2], srcs_record->data[3]); + return MOBI_DATA_CORRUPT; + } + + *data = srcs_record->data + archive_offset; + *size = srcs_record->size - archive_offset; + + return MOBI_SUCCESS; +} + +/** + @brief Get embedded conversion log + + Some mobi creator software store original conversion log together with source archive. + The function may return MOBI_SUCCESS even if the data was not found, + so it is neccessary to check whether returned data pointer is not NULL. + + @param[in,out] data Pointer to data offset in pdb record. + @param[in,out] size Pointer to data size + @param[in] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_get_embedded_log(unsigned char **data, size_t *size, const MOBIData *m) { + *data = NULL; + *size = 0; + if (m == NULL) { + return MOBI_INIT_FAILED; + } + MOBIMobiHeader *header = m->mh; + if (mobi_is_hybrid(m) && m->use_kf8 && m->next) { + /* SRCS index is in KF7 header */ + header = m->next->mh; + } + if (header == NULL || header->srcs_index == NULL || header->srcs_count == NULL || + *header->srcs_index == MOBI_NOTSET || *header->srcs_count < 2) { + return MOBI_SUCCESS; + } + uint32_t index = *header->srcs_index + 1; + + const MOBIPdbRecord *srcs_record = mobi_get_record_by_seqnumber(m, index); + if (srcs_record == NULL) { + return MOBI_SUCCESS; + } + const size_t log_offset = 12; + if (srcs_record->size <= log_offset) { + debug_print("Wrong size of CMET resource: %zu\n", srcs_record->size); + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init_null(srcs_record->data, srcs_record->size); + if (buf == NULL) { + return MOBI_MALLOC_FAILED; + } + if (mobi_buffer_match_magic(buf, CMET_MAGIC) == false) { + debug_print("%s\n", "Wrong magic for CMET resource"); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_setpos(buf, 8); + uint32_t log_length = mobi_buffer_get32(buf); + unsigned char *log_data = mobi_buffer_getpointer(buf, log_length); + if (buf->error != MOBI_SUCCESS) { + debug_print("CMET resource too short: %zu (log size: %u)\n", srcs_record->size, log_length); + mobi_buffer_free_null(buf); + return MOBI_DATA_CORRUPT; + } + + *data = log_data; + *size = log_length; + + mobi_buffer_free_null(buf); + return MOBI_SUCCESS; +} + +/** + @brief Replace part data with decoded font data + + @param[in,out] part MOBIPart structure containing font resource, decoded part type will be set in the structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_add_font_resource(MOBIPart *part) { + unsigned char *data = NULL; + size_t size = 0; + MOBI_RET ret = mobi_decode_font_resource(&data, &size, part); + if (ret != MOBI_SUCCESS) { + return ret; + } + part->data = data; + part->size = size; + part->type = mobi_determine_font_type(data, size); + /* FIXME: mark unknown font types as ttf (shouldn't happen). + This will allow proper font resource deallocation. */ + if (part->type == T_UNKNOWN) { part->type = T_TTF; } + return MOBI_SUCCESS; +} + +/** + @brief Deobfuscator and decompressor for font resources + + @param[in,out] decoded_font Pointer to memory to write to. Will be allocated. Must be freed by caller + @param[in,out] decoded_size Decoded font data size + @param[in,out] part MOBIPart structure containing font resource, decoded part type will be set in the structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_decode_font_resource(unsigned char **decoded_font, size_t *decoded_size, MOBIPart *part) { + if (part->size < FONT_HEADER_LEN) { + debug_print("Font resource record too short (%zu)\n", part->size); + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init(part->size); + if (buf == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + memcpy(buf->data, part->data, part->size); + struct header { + char magic[5]; + uint32_t decoded_size; + uint32_t flags; + uint32_t data_offset; + uint32_t xor_key_len; + uint32_t xor_key_offset; + }; + struct header h; + mobi_buffer_getstring(h.magic, buf, 4); + if (strncmp(h.magic, FONT_MAGIC, 4) != 0) { + debug_print("Wrong magic for font resource: %s\n", h.magic); + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + h.decoded_size = mobi_buffer_get32(buf); + if (h.decoded_size == 0 || h.decoded_size > FONT_SIZEMAX) { + debug_print("Invalid declared font resource size: %u\n", h.decoded_size); + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + h.flags = mobi_buffer_get32(buf); + h.data_offset = mobi_buffer_get32(buf); + h.xor_key_len = mobi_buffer_get32(buf); + h.xor_key_offset = mobi_buffer_get32(buf); + const uint32_t zlib_flag = 1; /* bit 0 */ + const uint32_t xor_flag = 2; /* bit 1 */ + if (h.flags & xor_flag && h.xor_key_len > 0) { + /* deobfuscate */ + if (h.data_offset > buf->maxlen || h.xor_key_len > buf->maxlen || h.xor_key_offset > buf->maxlen - h.xor_key_len) { + debug_print("%s\n", "Invalid obfuscated font data offsets"); + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_setpos(buf, h.data_offset); + const unsigned char *xor_key = buf->data + h.xor_key_offset; + size_t i = 0; + const size_t xor_limit = h.xor_key_len * MOBI_FONT_OBFUSCATED_BUFFER_COUNT; + while (buf->offset < buf->maxlen && i < xor_limit) { + buf->data[buf->offset++] ^= xor_key[i % h.xor_key_len]; + i++; + } + } + mobi_buffer_setpos(buf, h.data_offset); + *decoded_size = h.decoded_size; + *decoded_font = malloc(h.decoded_size); + if (*decoded_font == NULL) { + mobi_buffer_free(buf); + debug_print("%s", "Memory allocation failed\n"); + return MOBI_MALLOC_FAILED; + } + const unsigned char *encoded_font = buf->data + buf->offset; + const unsigned long encoded_size = buf->maxlen - buf->offset; + if (h.flags & zlib_flag) { + /* unpack */ + int ret = m_uncompress(*decoded_font, (unsigned long *) decoded_size, encoded_font, encoded_size); + if (ret != M_OK) { + mobi_buffer_free(buf); + free(*decoded_font); + debug_print("%s", "Font resource decompression failed\n"); + return MOBI_DATA_CORRUPT; + } + if (*decoded_size != h.decoded_size) { + mobi_buffer_free(buf); + free(*decoded_font); + debug_print("Decompressed font size (%zu) differs from declared (%i)\n", *decoded_size, h.decoded_size); + return MOBI_DATA_CORRUPT; + } + } else { + if (*decoded_size < encoded_size) { + mobi_buffer_free(buf); + free(*decoded_font); + debug_print("Font size in record (%lu) larger then declared (%zu)\n", encoded_size, *decoded_size); + return MOBI_DATA_CORRUPT; + } + memcpy(*decoded_font, encoded_font, encoded_size); + } + + mobi_buffer_free(buf); + return MOBI_SUCCESS; +} + +/** + @brief Get resource type (image, font) by checking its magic header + + @param[in] record MOBIPdbRecord structure containing unknown record type + @return MOBIFiletype file type, T_UNKNOWN if not determined, T_BREAK if end of records mark found + */ +MOBIFiletype mobi_determine_resource_type(const MOBIPdbRecord *record) { + /* Kindle supports GIF, BMP, JPG, PNG, SVG images. */ + /* GIF: 47 49 46 38 37 61 (GIF87a), 47 49 46 38 39 61 (GIF89a) */ + /* BMP: 42 4D (BM) + 4 byte file length le */ + /* JPG: FF D8 FF (header) + FF D9 (trailer) */ + /* PNG: 89 50 4E 47 0D 0A 1A 0A */ + /* SVG is XML-based format, so stored in flow parts */ + /* FONT: must be decoded */ + if (record->size < 4) { + return T_UNKNOWN; + } + const unsigned char jpg_magic[] = "\xff\xd8\xff"; + const unsigned char gif_magic[] = "\x47\x49\x46\x38"; + const unsigned char png_magic[] = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; + const unsigned char bmp_magic[] = "\x42\x4d"; + const unsigned char font_magic[] = FONT_MAGIC; + const unsigned char audio_magic[] = AUDI_MAGIC; + const unsigned char video_magic[] = VIDE_MAGIC; + const unsigned char boundary_magic[] = BOUNDARY_MAGIC; + const unsigned char eof_magic[] = EOF_MAGIC; + if (memcmp(record->data, jpg_magic, 3) == 0) { + return T_JPG; + } + if (memcmp(record->data, gif_magic, 4) == 0) { + return T_GIF; + } + if (record->size >= 8 && memcmp(record->data, png_magic, 8) == 0) { + return T_PNG; + } + if (memcmp(record->data, font_magic, 4) == 0) { + return T_FONT; + } + if (record->size >= 8 && memcmp(record->data, boundary_magic, 8) == 0) { + return T_BREAK; + } + if (memcmp(record->data, eof_magic, 4) == 0) { + return T_BREAK; + } + if (record->size >= 6 && memcmp(record->data, bmp_magic, 2) == 0) { + const size_t bmp_size = mobi_get32le(&record->data[2]); + if (record->size == bmp_size) { + return T_BMP; + } + } else if (memcmp(record->data, audio_magic, 4) == 0) { + return T_AUDIO; + } else if (memcmp(record->data, video_magic, 4) == 0) { + return T_VIDEO; + } + return T_UNKNOWN; +} + +/** + @brief Check if loaded MOBI data is KF7/KF8 hybrid file + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_is_hybrid(const MOBIData *m) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + if (m->kf8_boundary_offset != MOBI_NOTSET) { + return true; + } + return false; +} + +/** + @brief Check if loaded document is MOBI/BOOK Mobipocket format + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_is_mobipocket(const MOBIData *m) { + if (m == NULL || m->ph == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + if (strcmp(m->ph->type, "BOOK") == 0 && + strcmp(m->ph->creator, "MOBI") == 0) { + return true; + } + return false; +} + +/** + @brief Check if loaded document is TEXt/REAd format + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_is_textread(const MOBIData *m) { + if (m == NULL || m->ph == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + if (strcmp(m->ph->type, "TEXt") == 0 && + strcmp(m->ph->creator, "REAd") == 0) { + return true; + } + return false; +} + +/** + @brief Check if loaded document is dictionary + + @param[in] m MOBIData structure with loaded mobi header + @return true or false + */ +bool mobi_is_dictionary(const MOBIData *m) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + /* FIXME: works only for old non-KF8 formats */ + if (mobi_get_fileversion(m) < 8 && mobi_exists_orth(m)) { + debug_print("%s", "Dictionary detected\n"); + return true; + } + return false; +} + +/** + @brief Check if loaded document is encrypted + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_is_encrypted(const MOBIData *m) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + if ((mobi_is_mobipocket(m) || mobi_is_textread(m)) && m->rh && + (m->rh->encryption_type == MOBI_ENCRYPTION_V1 || + m->rh->encryption_type == MOBI_ENCRYPTION_V2)) { + return true; + } + return false; +} + +/** + @brief Check if DRM key is set for the document + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_has_drmkey(const MOBIData *m) { +#ifdef USE_ENCRYPTION + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + MOBIDrm *drm = m->internals; + return drm != NULL && drm->key != NULL; +#else + UNUSED(m); + return false; +#endif +} + +/** + @brief Check if DRM cookies are set for the document + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_has_drmcookies(const MOBIData *m) { +#ifdef USE_ENCRYPTION + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + MOBIDrm *drm = m->internals; + return drm != NULL && drm->cookies_count > 0; +#else + UNUSED(m); + return false; +#endif +} + +/** + @brief Check if loaded document is Print Replica type + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return true or false + */ +bool mobi_is_replica(const MOBIData *m) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return false; + } + if (m->rec && m->rh && m->rh->compression_type == MOBI_COMPRESSION_NONE) { + MOBIPdbRecord *rec = m->rec->next; + if (rec && rec->size >= sizeof(REPLICA_MAGIC)) { + return memcmp(rec->data, REPLICA_MAGIC, sizeof(REPLICA_MAGIC) - 1) == 0; + } + } + return false; +} + +/** + @brief Get mobi file version + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return MOBI document version, 1 if ancient version (no MOBI header) or MOBI_NOTSET if error + */ +size_t mobi_get_fileversion(const MOBIData *m) { + size_t version = 1; + if (m == NULL || m->ph == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_NOTSET; + } + if (strcmp(m->ph->type, "BOOK") == 0 && strcmp(m->ph->creator, "MOBI") == 0) { + if (m->mh && m->mh->header_length) { + uint32_t header_length = *m->mh->header_length; + if (header_length < MOBI_HEADER_V2_SIZE) { + version = 2; + } else if (m->mh->version && *m->mh->version > 1) { + if ((*m->mh->version > 2 && header_length < MOBI_HEADER_V3_SIZE) + || (*m->mh->version > 3 && header_length < MOBI_HEADER_V4_SIZE) + ||(*m->mh->version > 5 && header_length < MOBI_HEADER_V5_SIZE)) { + return MOBI_NOTSET; + } + version = *m->mh->version; + } + } + } + return version; +} + +/** + @brief Is file version 8 or above + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return True if file version is 8 or greater + */ +bool mobi_is_kf8(const MOBIData *m) { + const size_t version = mobi_get_fileversion(m); + if (version != MOBI_NOTSET && version >= 8) { + return true; + } + return false; +} + +/** + @brief Is file version 8 or above + + @param[in] rawml MOBIRawml structure with parsed document + @return True if file version is 8 or greater + */ +bool mobi_is_rawml_kf8(const MOBIRawml *rawml) { + if (rawml && rawml->version != MOBI_NOTSET && rawml->version >= 8) { + return true; + } + return false; +} + +/** + @brief Get maximal size of uncompressed text record + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return Size of text or MOBI_NOTSET if error + */ +uint16_t mobi_get_textrecord_maxsize(const MOBIData *m) { + uint16_t max_record_size = RECORD0_TEXT_SIZE_MAX; + if (m && m->rh) { + if (m->rh->text_record_size > RECORD0_TEXT_SIZE_MAX) { + max_record_size = m->rh->text_record_size; + } + if (mobi_exists_mobiheader(m) && mobi_get_fileversion(m) <= 3) { + /* workaround for some old files with records larger than declared record size */ + size_t text_length = (size_t) max_record_size * m->rh->text_record_count; + if (text_length <= RAWTEXT_SIZEMAX && m->rh->text_length > text_length) { + max_record_size = RECORD0_TEXT_SIZE_MAX * 2; + } + } + } + return max_record_size; +} + +/** + @brief Get maximal size of all uncompressed text records + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return Size of text or MOBI_NOTSET if error + */ +size_t mobi_get_text_maxsize(const MOBIData *m) { + if (m && m->rh) { + /* FIXME: is it safe to use data from Record 0 header? */ + if (m->rh->text_record_count > 0) { + uint16_t max_record_size = mobi_get_textrecord_maxsize(m); + size_t maxsize = (size_t) m->rh->text_record_count * (size_t) max_record_size; + if (mobi_exists_mobiheader(m) && mobi_get_fileversion(m) <= 3) { + /* workaround for some old files with records larger than declared record size */ + if (m->rh->text_length > maxsize) { + maxsize = m->rh->text_length; + } + } + if (maxsize > RAWTEXT_SIZEMAX) { + debug_print("Raw text too large (%zu)\n", maxsize); + return MOBI_NOTSET; + } + return maxsize; + } + } + return MOBI_NOTSET; +} + +/** + @brief Get sequential number of first resource record (image/font etc) + + @param[in] m MOBIData structure with loaded Record(s) 0 headers + @return Record number or MOBI_NOTSET if not set + */ +size_t mobi_get_first_resource_record(const MOBIData *m) { + /* is it hybrid file? */ + if (mobi_is_hybrid(m) && m->use_kf8) { + /* get first image index from KF7 mobi header */ + if (m->next->mh->image_index) { + return *m->next->mh->image_index; + } + } + /* try to get it from currently set mobi header */ + if (m->mh && m->mh->image_index) { + return *m->mh->image_index; + } + return MOBI_NOTSET; +} + + +/** + @brief Calculate exponentiation for unsigned base and exponent + + @param[in] base Base + @param[in] exp Exponent + @return Result of base raised by the exponent exp + */ +size_t mobi_pow(unsigned base, unsigned exp) { + size_t result = 1; + while(exp) { + if (exp & 1) { + result *= base; + } + exp >>= 1; + base *= base; + } + return result; +} + +/** + @brief Decode positive number from base 32 to base 10. + + Base 32 characters must be upper case. + Maximal supported value is VVVVVV. + + @param[in,out] decoded Base 10 output number + @param[in] encoded Base 32 input number + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_base32_decode(uint32_t *decoded, const char *encoded) { + if (!encoded || !decoded) { + debug_print("Error, null parameter (decoded: %p, encoded: %p)\n", (void *) decoded, (void *) encoded); + return MOBI_PARAM_ERR; + } + /* strip leading zeroes */ + while (*encoded == '0') { + encoded++; + } + size_t encoded_length = strlen(encoded); + /* Let's limit input to 6 chars. VVVVVV(32) is 0x3FFFFFFF */ + if (encoded_length > 6) { + debug_print("Base 32 number too big: %s\n", encoded); + return MOBI_PARAM_ERR; + } + const unsigned char *c = (unsigned char *) encoded; + unsigned len = (unsigned) encoded_length; + const unsigned base = 32; + *decoded = 0; + unsigned value; + while (*c) { + /* FIXME: not portable, should we care? */ + if (*c >= 'A' && *c <= 'V') { + value = *c - 'A' + 10; + } + else if (*c >= '0' && *c <= '9') { + value = *c - '0'; + } + else { + debug_print("Illegal character: \"%c\"\n", *c); + return MOBI_DATA_CORRUPT; + } + *decoded += value * mobi_pow(base, --len); + c++; + } + return MOBI_SUCCESS; +} + + +/** + @brief Get offset of KF8 Boundary for KF7/KF8 hybrid file cached in MOBIData structure + + @param[in] m MOBIData structure + @return KF8 Boundary sequential number or zero if not found + */ +size_t mobi_get_kf8offset(const MOBIData *m) { + /* check if we want to parse KF8 part of joint file */ + if (m->use_kf8 && m->kf8_boundary_offset != MOBI_NOTSET) { + return m->kf8_boundary_offset + 1; + } + return 0; +} + +/** + @brief Get sequential number of KF8 Boundary record for KF7/KF8 hybrid file + + This function gets KF8 boundary offset from EXTH header + + @param[in] m MOBIData structure + @return KF8 Boundary record sequential number or MOBI_NOTSET if not found + */ +size_t mobi_get_kf8boundary_seqnumber(const MOBIData *m) { + if (m == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_NOTSET; + } + const MOBIExthHeader *exth_tag = mobi_get_exthrecord_by_tag(m, EXTH_KF8BOUNDARY); + if (exth_tag != NULL) { + uint32_t rec_number = mobi_decode_exthvalue(exth_tag->data, exth_tag->size); + rec_number--; + const MOBIPdbRecord *record = mobi_get_record_by_seqnumber(m, rec_number); + if (record && record->size >= sizeof(BOUNDARY_MAGIC) - 1) { + if (memcmp(record->data, BOUNDARY_MAGIC, sizeof(BOUNDARY_MAGIC) - 1) == 0) { + return rec_number; + } + } + } + return MOBI_NOTSET; +} + +/** + @brief Get size of serialized exth record including padding + + @param[in] m MOBIData structure + @return Size of exth record, zero on failure + */ +uint32_t mobi_get_exthsize(const MOBIData *m) { + if (m == NULL || m->eh == NULL) { + return 0; + } + size_t size = 0; + MOBIExthHeader *curr = m->eh; + while (curr) { + size += curr->size + 8; + curr = curr->next; + } + if (size > 0) { + /* add header size */ + size += 12; + /* add padding */ + size += size % 4; + } + if (size > UINT32_MAX) { + return 0; + } + return (uint32_t) size; +} + +/** + @brief Get size of serialized DRM data + + @param[in] m MOBIData structure + @return Size of DRM data, zero on failure + */ +uint32_t mobi_get_drmsize(const MOBIData *m) { + if (m == NULL || !mobi_is_encrypted(m)) { + return 0; + } + size_t size = 0; + + if (m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + size = 51; + } else if (m->mh && m->mh->drm_size && *m->mh->drm_size > 0) { + size = *m->mh->drm_size; + } + + if (size > UINT32_MAX) { + return 0; + } + return (uint32_t) size; +} + +/** + @brief Get count of palm database records + + @param[in] m MOBIData structure + @return Count of records, zero on failure + */ +uint16_t mobi_get_records_count(const MOBIData *m) { + size_t count = 0; + if (m->rec) { + MOBIPdbRecord *curr = m->rec; + while (curr) { + count++; + curr = curr->next; + } + } + if (count > UINT16_MAX) { + return 0; + } + return (uint16_t) count; +} + +/** + @brief Remove null characters from char buffer + + @param[in,out] buffer Character buffer + @param[in,out] len Size of buffer, will be updated with new length + */ +void mobi_remove_zeros(unsigned char *buffer, size_t *len) { + size_t length = *len; + unsigned char *end = buffer + length; + unsigned char *buf = memchr(buffer, 0, length); + if (buf == NULL) { + return; + } + buf++; + size_t distance = 1; + while (buf < end) { + if (*buf) { + *(buf - distance) = *buf; + } else { + distance++; + } + buf++; + } + *len -= distance; +} + +/** + @brief Loader will parse KF7 part of hybrid file + + @param[in,out] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_kf7(MOBIData *m) { + if (m == NULL) { + return MOBI_INIT_FAILED; + } + m->use_kf8 = false; + return MOBI_SUCCESS; +} + +/** + @brief Loader will parse KF8 part of hybrid file + + This is the default option. + + @param[in,out] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_parse_kf8(MOBIData *m) { + if (m == NULL) { + return MOBI_INIT_FAILED; + } + m->use_kf8 = true; + return MOBI_SUCCESS; +} + +/** + @brief Remove KF7 version from hybrid file + + @param[in,out] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_remove_part_kf7(MOBIData *m) { + + // move resource records to KF8 part + + size_t start_kf7 = MOBI_NOTSET; + size_t start_kf8 = MOBI_NOTSET; + size_t count_kf7 = MOBI_NOTSET; + size_t count_kf8 = MOBI_NOTSET; + + // switch to KF7 data + if (m->use_kf8) { + mobi_swap_mobidata(m); + m->use_kf8 = false; + } + if (m->mh == NULL) { + debug_print("%s\n", "Mobi header for version 7 missing"); + return MOBI_INIT_FAILED; + } + if (m->mh->image_index) { + start_kf7 = *m->mh->image_index; + } + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_COUNTRESOURCES); + if (exth) { + count_kf7 = mobi_decode_exthvalue(exth->data, exth->size); + } + + // switch back to KF8 + mobi_swap_mobidata(m); + m->use_kf8 = true; + + if (m->mh == NULL || m->kf8_boundary_offset == MOBI_NOTSET) { + debug_print("%s\n", "Mobi header for version 8 missing"); + return MOBI_INIT_FAILED; + } + + if (m->mh->image_index) { + start_kf8 = *m->mh->image_index; + } + + MOBIExthHeader *exth_resources = mobi_get_exthrecord_by_tag(m, EXTH_COUNTRESOURCES); + if (exth_resources) { + count_kf8 = mobi_decode_exthvalue(exth_resources->data, exth_resources->size); + } + + if (start_kf7 == MOBI_NOTSET || start_kf8 == MOBI_NOTSET || + count_kf7 == MOBI_NOTSET || count_kf8 == MOBI_NOTSET || + m->kf8_boundary_offset < count_kf7) { + return MOBI_DATA_CORRUPT; + } + + // move resources to KF8 part + MOBIPdbRecord *extracted = mobi_extract_records_by_seqnumber(m, start_kf7, &count_kf7); + + m->kf8_boundary_offset -= count_kf7; + start_kf8 += m->kf8_boundary_offset + 1; + + MOBI_RET ret = mobi_insert_records_by_seqnumber(m, extracted, start_kf8); + if (ret != MOBI_SUCCESS) { + return ret; + } + + // delete records from beginning to boundary (inclusive) + size_t count = m->kf8_boundary_offset + 1; + + ret = mobi_delete_records_by_seqnumber(m, 0, &count); + if (ret != MOBI_SUCCESS) { + return ret; + } + m->kf8_boundary_offset = MOBI_NOTSET; + mobi_free_next(m); + + // update EXTH tags + + // update EXTH Count of Resources tag + count_kf8 += count_kf7; + if (exth_resources && exth_resources->size == 4 && count_kf8 <= UINT32_MAX) { + uint32_t value = (uint32_t) count_kf8; + unsigned char *p = exth_resources->data; + *p++ = (uint8_t)((uint32_t)(value & 0xff000000U) >> 24); + *p++ = (uint8_t)((uint32_t)(value & 0xff0000U) >> 16); + *p++ = (uint8_t)((uint32_t)(value & 0xff00U) >> 8); + *p = (uint8_t)((uint32_t)(value & 0xffU)); + } + + // check that EXTH Start Reading tag points to text, delete otherwise + MOBIExthHeader *exth_start = NULL; + while ((exth = mobi_next_exthrecord_by_tag(m, EXTH_STARTREADING, &exth_start))) { + uint32_t offset = mobi_decode_exthvalue(exth->data, exth->size); + if (offset > m->rh->text_record_count) { + mobi_delete_exthrecord(m, exth); + } + } + + // reset KF8 related EXTH flags + if (m->mh->exth_flags) { + *m->mh->exth_flags &= 0x7ff; + *m->mh->exth_flags |= 0x800; + } + + // adjust record offsets + if (m->mh->fdst_index && *m->mh->fdst_index + count_kf7 < UINT32_MAX) { + *m->mh->fdst_index += count_kf7; + } + if (m->mh->fcis_index && *m->mh->fcis_index + count_kf7 < UINT32_MAX) { + *m->mh->fcis_index += count_kf7; + } + if (m->mh->flis_index && *m->mh->flis_index + count_kf7 < UINT32_MAX) { + *m->mh->flis_index += count_kf7; + } + if (m->mh->datp_index && *m->mh->datp_index + count_kf7 < UINT32_MAX) { + *m->mh->datp_index += count_kf7; + } + if (m->mh->datp_rec_index && *m->mh->datp_rec_index + count_kf7 < UINT32_MAX) { + *m->mh->datp_rec_index += count_kf7; + } + + return MOBI_SUCCESS; +} + + +/** + @brief Remove KF8 version from hybrid file + + @param[in,out] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_remove_part_kf8(MOBIData *m) { + + if (m->use_kf8) { + mobi_swap_mobidata(m); + m->use_kf8 = false; + } + + if (m->mh == NULL) { + debug_print("%s\n", "Mobi header missing"); + return MOBI_INIT_FAILED; + } + + // delete records from boundary (inclusive) up to last eof (exclusive) + size_t start = m->kf8_boundary_offset; + size_t count = mobi_get_records_count(m); + if (start == MOBI_NOTSET || count <= start) { + debug_print("%s\n", "Bad records range data"); + return MOBI_DATA_CORRUPT; + } + count -= start + 1; + MOBI_RET ret = mobi_delete_records_by_seqnumber(m, start, &count); + if (ret != MOBI_SUCCESS) { + return ret; + } + + // delete source and logs records + if (m->mh->srcs_index && m->mh->srcs_count) { + start = *m->mh->srcs_index; + count = *m->mh->srcs_count; + if (start != MOBI_NOTSET && count != MOBI_NOTSET) { + ret = mobi_delete_records_by_seqnumber(m, start, &count); + if (ret != MOBI_SUCCESS) { + return ret; + } + *m->mh->srcs_index = MOBI_NOTSET; + *m->mh->srcs_count = 0; + } + } + + // truncate obsolete FONT, RESC records + if (m->mh->image_index && (start = *m->mh->image_index) != MOBI_NOTSET) { + MOBIPdbRecord *curr = mobi_get_record_by_seqnumber(m, start); + while (curr != NULL) { + if (curr->data && curr->size > 4 && + (memcmp(curr->data, FONT_MAGIC, 4) == 0 || + memcmp(curr->data, RESC_MAGIC, 4) == 0)) { + unsigned char *tmp = realloc(curr->data, 4); + if (tmp == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + curr->data = tmp; + curr->size = 4; + } + curr = curr->next; + } + } + + mobi_free_next(m); + + // update EXTH tags + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_KF8BOUNDARY); + if (exth != NULL && exth->size == sizeof(uint32_t)) { + const uint32_t value = MOBI_NOTSET; + memcpy(exth->data, &value, exth->size); + } + + ret = mobi_delete_exthrecord_by_tag(m, EXTH_KF8COVERURI); + if (ret != MOBI_SUCCESS) { + return ret; + } + + // reset KF8 related EXTH flags + if (m->mh->exth_flags){ + *m->mh->exth_flags &= 0x7ff; + } + + return MOBI_SUCCESS; +} + +/** + @brief Remove one version from hybrid file + + Hybrid file contains two document versions: KF8 version for devices that support new format and a version for older devices. + + @param[in,out] m MOBIData structure + @param[in] remove_kf8 Remove new KF8 part if true, old part if false + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_remove_hybrid_part(MOBIData *m, const bool remove_kf8) { + if (m == NULL) { + return MOBI_INIT_FAILED; + } + if (!mobi_is_hybrid(m)) { + debug_print("%s\n", "Not a hybrid, skip removing part"); + return MOBI_SUCCESS; + } + if (remove_kf8) { + return mobi_remove_part_kf8(m); + } + return mobi_remove_part_kf7(m); +} + +/** + @brief Swap KF7 and KF8 MOBIData structures in a hybrid file + + MOBIData structures form a circular linked list in case of hybrid files. + By default KF8 structure is first one in the list. + This function puts KF7 structure on the first place, so that it starts to be used by default. + + @param[in,out] m MOBIData structure + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_swap_mobidata(MOBIData *m) { + MOBIData *tmp = malloc(sizeof(MOBIData)); + if (tmp == NULL) { + debug_print("%s", "Memory allocation failed while swaping data\n"); + return MOBI_MALLOC_FAILED; + } + tmp->rh = m->rh; + tmp->mh = m->mh; + tmp->eh = m->eh; + m->rh = m->next->rh; + m->mh = m->next->mh; + m->eh = m->next->eh; + m->next->rh = tmp->rh; + m->next->mh = tmp->mh; + m->next->eh = tmp->eh; + free(tmp); + tmp = NULL; + return MOBI_SUCCESS; +} + +/** + @brief Store PID for encryption in MOBIData stucture. + PID will be calculated from device serial number. + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] serial Device serial number + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_setkey_serial(MOBIData *m, const char *serial) { +#ifdef USE_ENCRYPTION + return mobi_drmkey_set_serial(m, serial); +#else + UNUSED(m); + UNUSED(serial); + debug_print("Libmobi compiled without encryption support%s", "\n"); + return MOBI_DRM_UNSUPPORTED; +#endif +} + +/** + @brief Add DRM voucher + + DRM vouncher will be used to generate pid key which is used to encrypt main encryption key. + Pid key is based on device serial number. + Optionally it is possible to set validity of the key. The key will be valid only within the period. + Optionally the pid key may be generated not only from serial number but also from contents + of selected EXTH headers. In such case the headers should be added (@see mobi_add_exthrecord) + before calling this function and array of header tags passed as function parameter. + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] serial Device serial number + @param[in] valid_from DRM validity start time, -1 if not set + @param[in] valid_to DRM validity end time, -1 if not set + @param[in] tamperkeys Array of EXTH tags to include in PID generation, NULL if none + @param[in] tamperkeys_count Count of EXTH tags + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_addvoucher(MOBIData *m, const char *serial, const time_t valid_from, const time_t valid_to, + const MOBIExthTag *tamperkeys, const size_t tamperkeys_count) { +#ifdef USE_ENCRYPTION + return mobi_voucher_add(m, serial, valid_from, valid_to, tamperkeys, tamperkeys_count); + +#else + UNUSED(m); + UNUSED(serial); + UNUSED(valid_from); + UNUSED(valid_to); + UNUSED(tamperkeys); + UNUSED(tamperkeys_count); + debug_print("Libmobi compiled without encryption support%s", "\n"); + return MOBI_DRM_UNSUPPORTED; +#endif +} + +/** + @brief Store PID for encryption in MOBIData stucture + + @param[in,out] m MOBIData structure with raw data and metadata + @param[in] pid PID + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_setkey(MOBIData *m, const char *pid) { +#ifdef USE_ENCRYPTION + return mobi_drmkey_set(m, pid); +#else + UNUSED(m); + UNUSED(pid); + debug_print("Libmobi compiled without encryption support%s", "\n"); + return MOBI_DRM_UNSUPPORTED; +#endif +} + +/** + @brief Remove PID stored for encryption from MOBIData structure + + @param[in,out] m MOBIData structure with raw data and metadata + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +MOBI_RET mobi_drm_delkey(MOBIData *m) { +#ifdef USE_ENCRYPTION + return mobi_drmkey_delete(m); +#else + UNUSED(m); + debug_print("Libmobi compiled without encryption support%s", "\n"); + return MOBI_DRM_UNSUPPORTED; +#endif +} + +/** + @brief Free internals + + @param[in,out] m MOBIData structure with raw data and metadata + */ +void mobi_free_internals(MOBIData *m) { +#ifdef USE_ENCRYPTION + mobi_free_drm(m); +#else + UNUSED(m); +#endif +} + +/** + @brief Convert char buffer to 32-bit unsigned integer big endian + + @param[in] buf Input buffer + @return Converted value + */ +uint32_t mobi_get32be(const unsigned char buf[4]) { + uint32_t val = (uint32_t) buf[0] << 24; + val |= (uint32_t) buf[1] << 16; + val |= (uint32_t) buf[2] << 8; + val |= (uint32_t) buf[3]; + return val; +} + +/** + @brief Convert char buffer to 32-bit unsigned integer little endian + + @param[in] buf Input buffer + @return Converted value + */ +uint32_t mobi_get32le(const unsigned char buf[4]) { + uint32_t val = (uint32_t) buf[0]; + val |= (uint32_t) buf[1] << 8; + val |= (uint32_t) buf[2] << 16; + val |= (uint32_t) buf[3] << 24; + return val; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/util.h b/Charcoal/Charcoal/libmobi-public/src/util.h new file mode 100644 index 0000000..98b1698 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/util.h @@ -0,0 +1,157 @@ +/** @file util.h + * + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_util_h +#define libmobi_util_h + +#include "config.h" +#include "mobi.h" +#include "memory.h" +#include "buffer.h" +#include "read.h" +#include "compression.h" + +#ifndef HAVE_STRDUP +/** @brief strdup replacement */ +#define strdup mobi_strdup +#endif + +#ifdef USE_MINIZ +#include "miniz.h" +#define m_uncompress mz_uncompress +#define m_crc32 mz_crc32 +#define M_OK MZ_OK +#else +#include +#define m_uncompress uncompress +#define m_crc32 crc32 +#define M_OK Z_OK +#endif + +#define UNUSED(x) (void)(x) + +/** @brief Magic numbers of records */ +#define AUDI_MAGIC "AUDI" +#define CDIC_MAGIC "CDIC" +#define CMET_MAGIC "CMET" +#define EXTH_MAGIC "EXTH" +#define FDST_MAGIC "FDST" +#define FONT_MAGIC "FONT" +#define HUFF_MAGIC "HUFF" +#define IDXT_MAGIC "IDXT" +#define INDX_MAGIC "INDX" +#define LIGT_MAGIC "LIGT" +#define MOBI_MAGIC "MOBI" +#define ORDT_MAGIC "ORDT" +#define RESC_MAGIC "RESC" +#define SRCS_MAGIC "SRCS" +#define TAGX_MAGIC "TAGX" +#define VIDE_MAGIC "VIDE" +#define BOUNDARY_MAGIC "BOUNDARY" +#define EOF_MAGIC "\xe9\x8e\r\n" +#define REPLICA_MAGIC "%MOP" + +/** @brief Difference in seconds between epoch time and mac time */ +#define EPOCH_MAC_DIFF 2082844800UL + +/** + @defgroup mobi_pdb Params for pdb record header structure + @{ + */ +#define PALMDB_HEADER_LEN 78 /**< Length of header without record info headers */ +#define PALMDB_NAME_SIZE_MAX 32 /**< Max length of db name stored at offset 0 */ +#define PALMDB_RECORD_INFO_SIZE 8 /**< Record info header size of each pdb record */ +/** @} */ + +/** + @defgroup mobi_pdb_defs Default values for pdb record header structure + @{ + */ +#define PALMDB_ATTRIBUTE_DEFAULT 0 +#define PALMDB_VERSION_DEFAULT 0 +#define PALMDB_MODNUM_DEFAULT 0 +#define PALMDB_APPINFO_DEFAULT 0 +#define PALMDB_SORTINFO_DEFAULT 0 +#define PALMDB_TYPE_DEFAULT "BOOK" +#define PALMDB_CREATOR_DEFAULT "MOBI" +#define PALMDB_NEXTREC_DEFAULT 0 +/** @} */ + +/** + @defgroup mobi_rec0 Params for record0 header structure + @{ + */ +#define RECORD0_HEADER_LEN 16 /**< Length of Record 0 header */ +#define RECORD0_TEXT_SIZE_MAX 4096 /**< Max size of uncompressed text record */ +#define RECORD0_FULLNAME_SIZE_MAX 1024 /**< Max size to full name string */ +/** @} */ + +/** + @defgroup mobi_len Header length / size of records + @{ + */ +#define CDIC_HEADER_LEN 16 +#define CDIC_RECORD_MAXCNT 1024 +#define HUFF_CODELEN_MAX 16 +#define HUFF_HEADER_LEN 24 +#define HUFF_RECORD_MAXCNT 1024 +#define HUFF_RECORD_MINSIZE 2584 +#define FONT_HEADER_LEN 24 +#define MEDIA_HEADER_LEN 12 +#define FONT_SIZEMAX (50 * 1024 * 1024) +#define RAWTEXT_SIZEMAX 0xfffffff +#define MOBI_HEADER_V2_SIZE 0x18 +#define MOBI_HEADER_V3_SIZE 0x74 +#define MOBI_HEADER_V4_SIZE 0xd0 +#define MOBI_HEADER_V5_SIZE 0xe4 +#define MOBI_HEADER_V6_SIZE 0xe4 +#define MOBI_HEADER_V6_EXT_SIZE 0xe8 +#define MOBI_HEADER_V7_SIZE 0xe4 +/** @} */ + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#define MOBI_TITLE_SIZEMAX 1024 + +int mobi_bitcount(const uint8_t byte); +MOBI_RET mobi_delete_record_by_seqnumber(MOBIData *m, const size_t num); +MOBI_RET mobi_swap_mobidata(MOBIData *m); +char * mobi_strdup(const char *s); +bool mobi_is_cp1252(const MOBIData *m); +bool mobi_has_drmkey(const MOBIData *m); +bool mobi_has_drmcookies(const MOBIData *m); +MOBI_RET mobi_cp1252_to_utf8(char *output, const char *input, size_t *outsize, const size_t insize); +MOBI_RET mobi_utf8_to_cp1252(char *output, const char *input, size_t *outsize, const size_t insize); +uint8_t mobi_ligature_to_cp1252(const uint8_t byte1, const uint8_t byte2); +uint16_t mobi_ligature_to_utf16(const uint32_t byte1, const uint32_t byte2); +MOBIFiletype mobi_determine_resource_type(const MOBIPdbRecord *record); +MOBIFiletype mobi_determine_flowpart_type(const MOBIRawml *rawml, const size_t part_number); +MOBI_RET mobi_base32_decode(uint32_t *decoded, const char *encoded); +MOBIFiletype mobi_get_resourcetype_by_uid(const MOBIRawml *rawml, const size_t uid); +uint32_t mobi_get_exthsize(const MOBIData *m); +uint32_t mobi_get_drmsize(const MOBIData *m); +uint16_t mobi_get_records_count(const MOBIData *m); +void mobi_remove_zeros(unsigned char *buffer, size_t *len); +MOBI_RET mobi_add_audio_resource(MOBIPart *part); +MOBI_RET mobi_add_video_resource(MOBIPart *part); +MOBI_RET mobi_add_font_resource(MOBIPart *part); +MOBI_RET mobi_set_fullname(MOBIData *m, const char *fullname); +MOBI_RET mobi_set_pdbname(MOBIData *m, const char *name); +void mobi_free_internals(MOBIData *m); +uint32_t mobi_get32be(const unsigned char buf[4]); +uint32_t mobi_get32le(const unsigned char buf[4]); +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/win32/getopt.c b/Charcoal/Charcoal/libmobi-public/src/win32/getopt.c new file mode 100644 index 0000000..01bd693 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/win32/getopt.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "getopt.h" + +int opterr = 1, /* if error message should be printed */ +optind = 1, /* index into parent argv vector */ +optopt, /* character checked for validity */ +optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + const char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)printf("illegal option -- %c\n", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)printf("option requires an argument -- %c\n", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/Charcoal/Charcoal/libmobi-public/src/win32/getopt.h b/Charcoal/Charcoal/libmobi-public/src/win32/getopt.h new file mode 100644 index 0000000..3b15d46 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/win32/getopt.h @@ -0,0 +1,20 @@ +/** @file getopt.h +* +* Copyright (c) 2016 Bartek Fabiszewski +* http://www.fabiszewski.net +* +* Licensed under LGPL, either version 3, or any later. +* See +*/ + +/** Supply getopt header for Win32 builds */ + +#ifndef libmobi_getopt_h +#define libmobi_getopt_h + +extern int opterr, optind, optopt, optreset; +extern char *optarg; + +int getopt(int nargc, char *const nargv[], const char *ostr); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/write.c b/Charcoal/Charcoal/libmobi-public/src/write.c new file mode 100644 index 0000000..b626e03 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/write.c @@ -0,0 +1,540 @@ +/** @file write.c + * @brief Writing functions + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include + +#include "write.h" +#include "util.h" +#include "debug.h" +#ifdef USE_ENCRYPTION +#include "encryption.h" +#endif + +#define MOBI_HEADER_MAXLEN 280 +#define MOBI_RECORD0_PADDING 0x2002 + +/** + @brief Write buffer contents to file + + @param[in,out] file File descriptor + @param[in] buf Buffer + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_write_buffer(FILE *file, const MOBIBuffer *buf) { + const size_t written = fwrite(buf->data, 1, buf->maxlen, file); + if (written != buf->maxlen) { + debug_print("Writing failed (%s)\n", strerror(errno)); + return MOBI_WRITE_FAILED; + } + return MOBI_SUCCESS; +} + +/** + @brief Write palm database header to file + + @param[in,out] file File descriptor + @param[in] m MOBIData structure + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_write_pdbheader(FILE *file, const MOBIData *m) { + if (m == NULL || m->ph == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (file == NULL) { + debug_print("%s", "File not initialized\n"); + return MOBI_PARAM_ERR; + } + MOBIBuffer *buf = mobi_buffer_init(PALMDB_HEADER_LEN); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_addstring(buf, m->ph->name); + size_t len = strlen(m->ph->name); + mobi_buffer_addzeros(buf, PALMDB_NAME_SIZE_MAX - len); + mobi_buffer_add16(buf, m->ph->attributes); + mobi_buffer_add16(buf, m->ph->version); + mobi_buffer_add32(buf, m->ph->ctime); + mobi_buffer_add32(buf, m->ph->mtime); + mobi_buffer_add32(buf, m->ph->btime); + mobi_buffer_add32(buf, m->ph->mod_num); + mobi_buffer_add32(buf, m->ph->appinfo_offset); + mobi_buffer_add32(buf, m->ph->sortinfo_offset); + mobi_buffer_addstring(buf, m->ph->type); + mobi_buffer_addstring(buf, m->ph->creator); + mobi_buffer_add32(buf, m->ph->uid); + mobi_buffer_add32(buf, m->ph->next_rec); + m->ph->rec_count = mobi_get_records_count(m); + if (m->ph->rec_count == 0) { + mobi_buffer_free(buf); + debug_print("%s", "Zero records count\n"); + return MOBI_DATA_CORRUPT; + } + mobi_buffer_add16(buf, m->ph->rec_count); + if (buf->error != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + MOBI_RET ret = mobi_write_buffer(file, buf); + mobi_buffer_free(buf); + return ret; +} + +/** + @brief Serialize mobi header to buffer + + @param[in,out] buf output buffer + @param[in] m MOBIData structure + @param[in] exthsize Size of exth record + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_serialize_mobiheader(MOBIBuffer *buf, const MOBIData *m, const uint32_t exthsize) { + if (m == NULL || m->mh == NULL || buf == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + size_t buffer_init = buf->offset; + mobi_buffer_addstring(buf, m->mh->mobi_magic); + if (buf->offset > UINT32_MAX) { + debug_print("Offset too large: %zu\n", buf->offset); + return MOBI_DATA_CORRUPT; + } + uint32_t length_offset = (uint32_t) buf->offset; + uint32_t name_offset = 0; + uint32_t drm_offset = 0; + mobi_buffer_add32(buf, 0); /* dummy length */ + if (m->mh->mobi_type) { mobi_buffer_add32(buf, *m->mh->mobi_type); } else { goto finalize; } + if (m->mh->text_encoding) { mobi_buffer_add32(buf, *m->mh->text_encoding); } else { goto finalize; } + if (m->mh->uid) { mobi_buffer_add32(buf, *m->mh->uid); } else { goto finalize; } + bool isKF8 = false; + if (m->mh->version) { + mobi_buffer_add32(buf, *m->mh->version); + if (*m->mh->version == 8) { + isKF8 = true; + } + } else { goto finalize; } + if (m->mh->orth_index) { mobi_buffer_add32(buf, *m->mh->orth_index); } else { goto finalize; } + if (m->mh->infl_index) { mobi_buffer_add32(buf, *m->mh->infl_index); } else { goto finalize; } + if (m->mh->names_index) { mobi_buffer_add32(buf, *m->mh->names_index); } else { goto finalize; } + if (m->mh->keys_index) { mobi_buffer_add32(buf, *m->mh->keys_index); } else { goto finalize; } + if (m->mh->extra0_index) { mobi_buffer_add32(buf, *m->mh->extra0_index); } else { goto finalize; } + if (m->mh->extra1_index) { mobi_buffer_add32(buf, *m->mh->extra1_index); } else { goto finalize; } + if (m->mh->extra2_index) { mobi_buffer_add32(buf, *m->mh->extra2_index); } else { goto finalize; } + if (m->mh->extra3_index) { mobi_buffer_add32(buf, *m->mh->extra3_index); } else { goto finalize; } + if (m->mh->extra4_index) { mobi_buffer_add32(buf, *m->mh->extra4_index); } else { goto finalize; } + if (m->mh->extra5_index) { mobi_buffer_add32(buf, *m->mh->extra5_index); } else { goto finalize; } + if (m->mh->non_text_index) { mobi_buffer_add32(buf, *m->mh->non_text_index); } else { goto finalize; } + if (m->mh->full_name) { + if (buf->offset > UINT32_MAX) { + debug_print("Offset too large: %zu\n", buf->offset); + return MOBI_DATA_CORRUPT; + } + name_offset = (uint32_t) buf->offset; + mobi_buffer_add32(buf, MOBI_NOTSET); + mobi_buffer_add32(buf, 0); + } else { goto finalize; } + if (m->mh->locale) { mobi_buffer_add32(buf, *m->mh->locale); } else { goto finalize; } + if (m->mh->dict_input_lang) { mobi_buffer_add32(buf, *m->mh->dict_input_lang); } else { goto finalize; } + if (m->mh->dict_output_lang) { mobi_buffer_add32(buf, *m->mh->dict_output_lang); } else { goto finalize; } + if (m->mh->min_version) { mobi_buffer_add32(buf, *m->mh->min_version); } else { goto finalize; } + if (m->mh->image_index) { mobi_buffer_add32(buf, *m->mh->image_index); } else { goto finalize; } + if (m->mh->huff_rec_index) { mobi_buffer_add32(buf, *m->mh->huff_rec_index); } else { goto finalize; } + if (m->mh->huff_rec_count) { mobi_buffer_add32(buf, *m->mh->huff_rec_count); } else { goto finalize; } + if (m->mh->datp_rec_index) { mobi_buffer_add32(buf, *m->mh->datp_rec_index); } else { goto finalize; } + if (m->mh->datp_rec_count) { mobi_buffer_add32(buf, *m->mh->datp_rec_count); } else { goto finalize; } + if (m->mh->exth_flags) { mobi_buffer_add32(buf, *m->mh->exth_flags); } else { goto finalize; } + mobi_buffer_addzeros(buf, 32); /* 32 unknown bytes */ + if (m->mh->unknown6) { mobi_buffer_add32(buf, *m->mh->unknown6); } else { goto finalize; } + if (m->mh->drm_offset) { + drm_offset = (uint32_t) buf->offset; + mobi_buffer_add32(buf, *m->mh->drm_offset); + } else { goto finalize; } + if (m->mh->drm_count) { mobi_buffer_add32(buf, *m->mh->drm_count); } else { goto finalize; } + if (m->mh->drm_size) { mobi_buffer_add32(buf, *m->mh->drm_size); } else { goto finalize; } + if (m->mh->drm_flags) { mobi_buffer_add32(buf, *m->mh->drm_flags); } else { goto finalize; } + mobi_buffer_addzeros(buf, 8); /* 8 unknown bytes */ + if (isKF8) { + if (m->mh->fdst_index) { mobi_buffer_add32(buf, *m->mh->fdst_index); } else { goto finalize; } + } else { + if (m->mh->first_text_index) { mobi_buffer_add16(buf, *m->mh->first_text_index); } else { goto finalize; } + if (m->mh->last_text_index) { mobi_buffer_add16(buf, *m->mh->last_text_index); } else { goto finalize; } + } + if (m->mh->fdst_section_count) { mobi_buffer_add32(buf, *m->mh->fdst_section_count); } else { goto finalize; } + if (m->mh->fcis_index) { mobi_buffer_add32(buf, *m->mh->fcis_index); } else { goto finalize; } + if (m->mh->fcis_count) { mobi_buffer_add32(buf, *m->mh->fcis_count); } else { goto finalize; } + if (m->mh->flis_index) { mobi_buffer_add32(buf, *m->mh->flis_index); } else { goto finalize; } + if (m->mh->flis_count) { mobi_buffer_add32(buf, *m->mh->flis_count); } else { goto finalize; } + if (m->mh->unknown10) { mobi_buffer_add32(buf, *m->mh->unknown10); } else { goto finalize; } + if (m->mh->unknown11) { mobi_buffer_add32(buf, *m->mh->unknown11); } else { goto finalize; } + if (m->mh->srcs_index) { mobi_buffer_add32(buf, *m->mh->srcs_index); } else { goto finalize; } + if (m->mh->srcs_count) { mobi_buffer_add32(buf, *m->mh->srcs_count); } else { goto finalize; } + if (m->mh->unknown12) { mobi_buffer_add32(buf, *m->mh->unknown12); } else { goto finalize; } + if (m->mh->unknown13) { mobi_buffer_add32(buf, *m->mh->unknown13); } else { goto finalize; } + mobi_buffer_addzeros(buf, 2); /* 2 unknown bytes */ + if (m->mh->extra_flags) { mobi_buffer_add16(buf, *m->mh->extra_flags); } else { goto finalize; } + if (m->mh->ncx_index) { mobi_buffer_add32(buf, *m->mh->ncx_index); } else { goto finalize; } + if (isKF8) { + if (m->mh->fragment_index) { mobi_buffer_add32(buf, *m->mh->fragment_index); } else { goto finalize; } + if (m->mh->skeleton_index) { mobi_buffer_add32(buf, *m->mh->skeleton_index); } else { goto finalize; } + } else { + if (m->mh->unknown14) { mobi_buffer_add32(buf, *m->mh->unknown14); } else { goto finalize; } + if (m->mh->unknown15) { mobi_buffer_add32(buf, *m->mh->unknown15); } else { goto finalize; } + } + if (m->mh->datp_index) { mobi_buffer_add32(buf, *m->mh->datp_index); } else { goto finalize; } + if (isKF8) { + if (m->mh->guide_index) { mobi_buffer_add32(buf, *m->mh->guide_index); } else { goto finalize; } + } else { + if (m->mh->unknown16) { mobi_buffer_add32(buf, *m->mh->unknown16); } else { goto finalize; } + } + if (m->mh->unknown17) { mobi_buffer_add32(buf, *m->mh->unknown17); } else { goto finalize; } + if (m->mh->unknown18) { mobi_buffer_add32(buf, *m->mh->unknown18); } else { goto finalize; } + if (m->mh->unknown19) { mobi_buffer_add32(buf, *m->mh->unknown19); } else { goto finalize; } + if (m->mh->unknown20) { mobi_buffer_add32(buf, *m->mh->unknown20); } else { goto finalize; } + +finalize: + if (buf->error != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + size_t headersize = buf->offset - buffer_init; + if (headersize > UINT32_MAX) { + debug_print("Header too large: %zu\n", headersize); + return MOBI_DATA_CORRUPT; + } + size_t saved_offset = buf->offset; + /* write header length at offset 20 */ + mobi_buffer_setpos(buf, length_offset); + mobi_buffer_add32(buf, (uint32_t) headersize); + *m->mh->header_length = (uint32_t) headersize; + uint32_t drmsize = 0; +#ifdef USE_ENCRYPTION + if (m->rh->encryption_type == MOBI_ENCRYPTION_V2 && + m->mh->drm_size && m->mh->drm_offset && *m->mh->drm_size > 0) { + drmsize = mobi_get_drmsize(m); + *m->mh->drm_offset = RECORD0_HEADER_LEN + (uint32_t) headersize + exthsize; + mobi_buffer_setpos(buf, drm_offset); + mobi_buffer_add32(buf, *m->mh->drm_offset); + } else if (m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + drmsize = mobi_get_drmsize(m); + } +#endif + + if (m->mh->full_name) { + /* full name's offset is after exth records */ + uint32_t fullname_offset = RECORD0_HEADER_LEN + (uint32_t) headersize + exthsize + drmsize; + size_t fullname_length = strlen(m->mh->full_name); + if (fullname_length > MOBI_TITLE_SIZEMAX) { + fullname_length = MOBI_TITLE_SIZEMAX; + m->mh->full_name[MOBI_TITLE_SIZEMAX] = '\0'; + } + /* write fullname offset and length */ + mobi_buffer_setpos(buf, name_offset); + mobi_buffer_add32(buf, fullname_offset); + mobi_buffer_add32(buf, (uint32_t) fullname_length); + if (m->mh->full_name_offset == NULL) { + m->mh->full_name_offset = malloc(sizeof(uint32_t)); + if (m->mh->full_name_offset == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + *m->mh->full_name_offset = fullname_offset; + if (m->mh->full_name_length == NULL) { + m->mh->full_name_length = malloc(sizeof(uint32_t)); + if (m->mh->full_name_length == NULL) { + debug_print("Memory allocation failed%s", "\n"); + return MOBI_MALLOC_FAILED; + } + } + *m->mh->full_name_length = (uint32_t) fullname_length; + } + mobi_buffer_setpos(buf, saved_offset); + if (buf->error != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + return MOBI_SUCCESS; +} + +/** + @brief Serialize exth header to buffer + + @param[in,out] buf output buffer + @param[in] m MOBIData structure + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_serialize_extheader(MOBIBuffer *buf, const MOBIData *m) { + if (m == NULL || m->eh == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + MOBIExthHeader *curr = m->eh; + mobi_buffer_addstring(buf, EXTH_MAGIC); + const size_t length_offset = buf->offset; + size_t length = 12; /* start with header length */ + mobi_buffer_add32(buf, 0); + const size_t count_offset = buf->offset; + size_t count = 0; + mobi_buffer_add32(buf, 0); + while (curr) { + /* total size = data size plus 8 bytes for uid and size */ + const uint32_t size = curr->size + 8; + length += size; + count++; + mobi_buffer_add32(buf, curr->tag); + mobi_buffer_add32(buf, size); + mobi_buffer_addraw(buf, curr->data, curr->size); + if (buf->error != MOBI_SUCCESS) { + return MOBI_DATA_CORRUPT; + } + curr = curr->next; + } + if (length > UINT32_MAX || count > UINT32_MAX) { + debug_print("Length (%zu) or count (%zu) too large\n", length, count); + return MOBI_DATA_CORRUPT; + } + /* add padding */ + const size_t padding_size = length % 4; + length += padding_size; + mobi_buffer_addzeros(buf, padding_size); + const size_t saved_offset = buf->offset; + mobi_buffer_setpos(buf, length_offset); + mobi_buffer_add32(buf, (uint32_t) length); + mobi_buffer_setpos(buf, count_offset); + mobi_buffer_add32(buf, (uint32_t) count); + mobi_buffer_setpos(buf, saved_offset); + return MOBI_SUCCESS; +} + +/** + @brief Serialize record0 and update record in MOBIData structure. + + Record0 sequential number may be greater than zero in case + of hybrid file with two info records + + @param[in,out] m MOBIData structure + @param[in] seqnumber Record0 sequential number + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_update_record0(MOBIData *m, const size_t seqnumber) { + if (m == NULL || m->rh == NULL || m->rec == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + size_t padding = MOBI_RECORD0_PADDING; + if (!mobi_exists_mobiheader(m)) { + padding = 0; + } else if (mobi_get_fileversion(m) < 8) { + padding -= 12; + } + size_t record0_maxlen = RECORD0_HEADER_LEN + MOBI_HEADER_MAXLEN; + uint32_t exthsize = mobi_get_exthsize(m); + uint32_t drmsize = mobi_get_drmsize(m); + record0_maxlen += exthsize; + record0_maxlen += drmsize; + record0_maxlen += MOBI_TITLE_SIZEMAX; + record0_maxlen += padding; + MOBIBuffer *buf = mobi_buffer_init(record0_maxlen); + if (buf == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return MOBI_MALLOC_FAILED; + } + mobi_buffer_add16(buf, m->rh->compression_type); + mobi_buffer_addzeros(buf, 2); + mobi_buffer_add32(buf, m->rh->text_length); + mobi_buffer_add16(buf, m->rh->text_record_count); + mobi_buffer_add16(buf, m->rh->text_record_size); + mobi_buffer_add16(buf, m->rh->encryption_type); + mobi_buffer_add16(buf, m->rh->unknown1); + + if (m->mh) { + MOBI_RET ret = mobi_serialize_mobiheader(buf, m, exthsize); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return ret; + } + if (m->eh) { + ret = mobi_serialize_extheader(buf, m); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return ret; + } + } + +#ifdef USE_ENCRYPTION + if (m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + ret = mobi_drm_serialize_v1(buf, m); + } else if (m->rh->encryption_type == MOBI_ENCRYPTION_V2) { + ret = mobi_drm_serialize_v2(buf, m); + } + if (ret != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return ret; + } +#endif + if (m->mh->full_name && m->mh->full_name_offset) { + mobi_buffer_setpos(buf, *m->mh->full_name_offset); + mobi_buffer_addstring(buf, m->mh->full_name); + if (buf->error != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + } + } +#ifdef USE_ENCRYPTION + else if (m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + MOBI_RET ret = mobi_drm_serialize_v1(buf, m); + if (ret != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return ret; + } + mobi_buffer_setpos(buf, 14 + drmsize); + } +#endif + + mobi_buffer_addzeros(buf, padding); + if (buf->error) { + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + + MOBIPdbRecord *record0 = mobi_get_record_by_seqnumber(m, seqnumber); + if (record0 == NULL) { + debug_print("%s", "Record 0 not initialized\n"); + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + unsigned char *data = malloc(buf->offset); + if (data == NULL) { + mobi_buffer_free(buf); + return MOBI_MALLOC_FAILED; + } + memcpy(data, buf->data, buf->offset); + record0->size = buf->offset; + mobi_buffer_free(buf); + if (record0->data) { + free(record0->data); + } + record0->data = data; + return MOBI_SUCCESS; +} + +/** + @brief Write palm database records to file + + @param[in,out] file File descriptor + @param[in] m MOBIData structure + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_write_records(FILE *file, const MOBIData *m) { + if (m == NULL || m->rec == NULL) { + debug_print("%s", "Mobi structure not initialized\n"); + return MOBI_INIT_FAILED; + } + if (file == NULL) { + return MOBI_PARAM_ERR; + } + long pos = ftell(file); + if (pos < 0) { + return MOBI_WRITE_FAILED; + } + uint32_t offset = (uint32_t) pos; + /* 8 bytes per record meta plus 2 bytes padding */ + offset += 8 * m->ph->rec_count + 2; + MOBIPdbRecord *curr = m->rec; + uint32_t i = 0; + while (curr) { + if (offset > UINT32_MAX) { + return MOBI_DATA_CORRUPT; + } + MOBIBuffer *buf = mobi_buffer_init(PALMDB_RECORD_INFO_SIZE); + if (buf == NULL) { + return MOBI_MALLOC_FAILED; + } + mobi_buffer_add32(buf, (uint32_t) offset); + offset += curr->size; + mobi_buffer_add8(buf, curr->attributes); + curr->uid = 2 * i++; + const uint8_t h = (uint8_t) ((curr->uid & 0xff0000U) >> 16); + const uint16_t l = (uint16_t) (curr->uid & 0xffffU); + mobi_buffer_add8(buf, h); + mobi_buffer_add16(buf, l); + if (buf->error != MOBI_SUCCESS) { + mobi_buffer_free(buf); + return MOBI_DATA_CORRUPT; + } + MOBI_RET ret = mobi_write_buffer(file, buf); + mobi_buffer_free(buf); + if (ret != MOBI_SUCCESS) { + return ret; + } + curr = curr->next; + } + char padding[2] = { 0 }; + size_t written = fwrite(padding, 1, sizeof(padding), file); + if (written != sizeof(padding)) { + debug_print("Writing failed (%s)\n", strerror(errno)); + return MOBI_WRITE_FAILED; + } + + curr = m->rec; + while (curr) { + written = fwrite(curr->data, 1, curr->size, file); + if (written != curr->size) { + debug_print("Writing failed (%s)\n", strerror(errno)); + return MOBI_WRITE_FAILED; + } + curr = curr->next; + } + return MOBI_SUCCESS; +} + +/** + @brief Write mobi document to file. + + Serializes metadata from MOBIData into raw records also stored in MOBIData (m->rec). + Later writes palm database to file. + + @param[in,out] file File descriptor + @param[in,out] m MOBIData structure + @return MOBI_RET status code (MOBI_SUCCESS on success) + */ +MOBI_RET mobi_write_file(FILE *file, MOBIData *m) { + MOBI_RET ret = mobi_write_pdbheader(file, m); + if (ret != MOBI_SUCCESS) { + return ret; + } + MOBIData *m_kf7 = m; + if (mobi_is_hybrid(m) && m->next) { + MOBIData *m_kf8 = m; + if (m->use_kf8 == false) { + m_kf8 = m->next; + } else { + m_kf7 = m->next; + } + const size_t record0_kf8_offset = m_kf8->kf8_boundary_offset + 1; + ret = mobi_update_record0(m_kf8, record0_kf8_offset); + if (ret != MOBI_SUCCESS) { + return ret; + } + } + ret = mobi_update_record0(m_kf7, 0); + if (ret != MOBI_SUCCESS) { + return ret; + } + ret = mobi_write_records(file, m); + if (ret != MOBI_SUCCESS) { + return ret; + } + return MOBI_SUCCESS; + +} diff --git a/Charcoal/Charcoal/libmobi-public/src/write.h b/Charcoal/Charcoal/libmobi-public/src/write.h new file mode 100644 index 0000000..4eed087 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/write.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2014 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_write_h +#define libmobi_write_h + +#include "config.h" +#include "mobi.h" +#include "buffer.h" + + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/src/xmlwriter.c b/Charcoal/Charcoal/libmobi-public/src/xmlwriter.c new file mode 100644 index 0000000..8c8fe4f --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/xmlwriter.c @@ -0,0 +1,918 @@ +/** @file xmlwriter.c + * @brief Implements a simplified subset of libxml2 functions used in libmobi. + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#define _GNU_SOURCE 1 +#ifndef __USE_BSD +#define __USE_BSD /* for strdup on linux/glibc */ +#endif + +#include +#include +#include "xmlwriter.h" +#include "debug.h" +#include "util.h" +#include "parse_rawml.h" + +#define MOBI_XML_BUFFERSIZE 4096 +#define MOBI_XML_STATESSIZE 200 +#define XML_ERROR -1 +#define XML_OK 0 + +/** + @brief Initiate xml states with first name and mode pair + + @param[in] name MOBIRawml State element name + @param[in] mode MOBIRawml State mode + @return New state + */ +static MOBIXmlState * mobi_xml_state_init(const char *name, const MOBI_XML_MODE mode) { + MOBIXmlState *curr = calloc(1, sizeof(MOBIXmlState)); + if (curr == NULL) { + return NULL; + } + curr->name = strdup(name); + if (curr->name == NULL) { + free(curr); + return NULL; + } + curr->mode = mode; + return curr; +} + +/** + @brief Get current active state from the list + + @param[in] writer xmlTextWriter + @return State + */ +static MOBIXmlState * mobi_xml_state_current(const xmlTextWriterPtr writer) { + return writer->states; +} + +/** + @brief Add new state to the list + + @param[in,out] writer xmlTextWriter + @param[in] name MOBIRawml State element name + @param[in] mode MOBIRawml State mode + @return Added state + */ +static MOBIXmlState * mobi_xml_state_push(xmlTextWriterPtr writer, const char *name, const MOBI_XML_MODE mode) { + MOBIXmlState *new = mobi_xml_state_init(name, mode); + MOBIXmlState *first = writer->states; + if (!first) { + writer->states = new; + } else { + new->next = first; + writer->states = new; + } + return writer->states; +} + +/** + @brief Remove state from the list + + @param[in] state State structure that will be deleted + @return Next state in the list or NULL if not present + */ +static MOBIXmlState * mobi_xml_state_del(MOBIXmlState *state) { + MOBIXmlState *del = state; + state = state->next; + free(del->name); + free(del); + del = NULL; + return state; +} + +/** + @brief Remove state from the beginning of the list + + @param[in,out] writer xmlTextWriter + @return Next state or NULL if not present + */ +static MOBIXmlState * mobi_xml_state_pop(xmlTextWriterPtr writer) { + writer->states = mobi_xml_state_del(writer->states); + return writer->states; +} + +/** + @brief Remove all states from the list + + @param[in,out] first First state from the list + */ +static void mobi_xml_state_delall(MOBIXmlState *first) { + while (first) { + first = mobi_xml_state_del(first); + } +} + +/** + @brief Get current level of nested element + + @param[in] writer xmlTextWriter + @return Level + */ +static size_t mobi_xml_level(const xmlTextWriterPtr writer) { + MOBIXmlState *curr = writer->states; + size_t level = 0; + while (curr) { + level++; + if (curr->next == NULL) { + break; + } + curr = curr->next; + } + return level; +} + +/** + @brief Write string to xml buffer + + @param[in,out] writer xmlTextWriter + @param[in] string String + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_buffer_addstring(xmlTextWriterPtr writer, const char *string) { + if (writer == NULL || writer->xmlbuf == NULL || writer->xmlbuf->mobibuffer == NULL || string == NULL) { + return MOBI_INIT_FAILED; + } + MOBIBuffer *buf = writer->xmlbuf->mobibuffer; + mobi_buffer_addstring(buf, string); + if (buf->error == MOBI_BUFFER_END) { + mobi_buffer_resize(buf, buf->maxlen * 2); + if (buf->error != MOBI_SUCCESS) { + return buf->error; + } + /* update xmlbuf->content */ + writer->xmlbuf->content = writer->xmlbuf->mobibuffer->data; + mobi_xml_buffer_addstring(writer, string); + } + return buf->error; +} + +/** + @brief Write character to xml buffer + + @param[in,out] writer xmlTextWriter + @param[in] c Character + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_buffer_addchar(xmlTextWriterPtr writer, const unsigned char c) { + if (writer == NULL || writer->xmlbuf == NULL || writer->xmlbuf->mobibuffer == NULL) { + return MOBI_INIT_FAILED; + } + MOBIBuffer *buf = writer->xmlbuf->mobibuffer; + mobi_buffer_add8(buf, c); + if (buf->error == MOBI_BUFFER_END) { + mobi_buffer_resize(buf, buf->maxlen * 2); + if (buf->error != MOBI_SUCCESS) { + return buf->error; + } + /* update xmlbuf->content */ + writer->xmlbuf->content = writer->xmlbuf->mobibuffer->data; + mobi_xml_buffer_addchar(writer, c); + } + return buf->error; +} + +/** + @brief Write terminating null character to xml buffer + + @param[in,out] writer xmlTextWriter + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_buffer_flush(xmlTextWriterPtr writer) { + return mobi_xml_buffer_addchar(writer, '\0'); +} + +/** + @brief Write string with encoded reserved characters to xml buffer + + @param[in,out] writer xmlTextWriter + @param[in] string String + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_buffer_addencoded(xmlTextWriterPtr writer, const char *string) { + if (string == NULL) { + return MOBI_INIT_FAILED; + } + MOBI_RET ret = MOBI_SUCCESS; + unsigned char *p = (unsigned char *)string; + unsigned char c; + while ((c = *p++)) { + switch (c) { + case '<': + ret = mobi_xml_buffer_addstring(writer, "<"); + break; + case '>': + ret = mobi_xml_buffer_addstring(writer, ">"); + break; + case '&': + ret = mobi_xml_buffer_addstring(writer, "&"); + break; + case '"': + ret = mobi_xml_buffer_addstring(writer, """); + break; + case '\r': + ret = mobi_xml_buffer_addstring(writer, " "); + break; + default: + ret = mobi_xml_buffer_addchar(writer, c); + break; + } + if (ret != MOBI_SUCCESS) { + break; + } + } + return ret; +} + +/** + @brief Write attribute value with encoded reserved characters to xml buffer + + @param[in,out] writer xmlTextWriter + @param[in] string String + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_buffer_addencoded_attr(xmlTextWriterPtr writer, const char *string) { + if (string == NULL) { + return MOBI_INIT_FAILED; + } + MOBI_RET ret = MOBI_SUCCESS; + unsigned char *p = (unsigned char *)string; + unsigned char c; + while ((c = *p++)) { + switch (c) { + case '<': + ret = mobi_xml_buffer_addstring(writer, "<"); + break; + case '>': + ret = mobi_xml_buffer_addstring(writer, ">"); + break; + case '&': + ret = mobi_xml_buffer_addstring(writer, "&"); + break; + case '"': + ret = mobi_xml_buffer_addstring(writer, """); + break; + case '\r': + ret = mobi_xml_buffer_addstring(writer, " "); + break; + case '\n': + ret = mobi_xml_buffer_addstring(writer, " "); + break; + case '\t': + ret = mobi_xml_buffer_addstring(writer, " "); + break; + default: + ret = mobi_xml_buffer_addchar(writer, c); + break; + } + if (ret != MOBI_SUCCESS) { + break; + } + } + return ret; +} + +/** + @brief Write indent to xml buffer + + @param[in,out] writer xmlTextWriter + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_write_indent(xmlTextWriterPtr writer) { + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return MOBI_INIT_FAILED; + } + size_t levels_count = mobi_xml_level(writer); + if (levels_count > 0) { + /* don't indent first level */ + levels_count--; + } + MOBI_RET ret = MOBI_SUCCESS; + while (levels_count--) { + ret = mobi_xml_buffer_addchar(writer, ' '); + if (ret != MOBI_SUCCESS) { + break; + } + } + return ret; +} + +/** + @brief Write namespace declaration if needed + + @param[in,out] writer xmlTextWriter + */ +static void mobi_xml_write_ns(xmlTextWriterPtr writer) { + if (writer && writer->nsname && writer->nsvalue) { + xmlTextWriterWriteAttribute(writer, (unsigned char *) writer->nsname, (unsigned char *) writer->nsvalue); + free(writer->nsname); + writer->nsname = NULL; + free(writer->nsvalue); + writer->nsvalue = NULL; + } +} + +/** + @brief Save namespace declaration parameters + + @param[in,out] writer xmlTextWriter + @param[in] nsname NS attribute name + @param[in] nsvalue NS attribute value + @return MOBI_RET status code (on success MOBI_SUCCESS) + */ +static MOBI_RET mobi_xml_save_ns(xmlTextWriterPtr writer, const char *nsname, const char *nsvalue) { + /* Only one declaration should be enough for libmobi */ + if (writer && writer->nsname == NULL && writer->nsvalue == NULL) { + writer->nsname = strdup(nsname); + if (writer->nsname == NULL) { + return MOBI_MALLOC_FAILED; + } + writer->nsvalue = strdup(nsvalue); + if (writer->nsvalue == NULL) { + return MOBI_MALLOC_FAILED; + } + } + return MOBI_SUCCESS; +} + + +/* + + Libxml2 compatible functions + + */ + +/** + @brief Create xml buffer + + Libxml2 compatibility wrapper for MOBIBuffer structure. + Must be deallocated with xmlBufferFree + + @return Buffer pointer + */ +xmlBufferPtr xmlBufferCreate(void) { + xmlBufferPtr xmlbuf = NULL; + xmlbuf = malloc(sizeof(xmlBuffer)); + if (xmlbuf == NULL) { + debug_print("%s", "Buffer allocation failed\n"); + return NULL; + } + unsigned int size = MOBI_XML_BUFFERSIZE; + MOBIBuffer *buf = mobi_buffer_init(size); + if (buf == NULL) { + free(xmlbuf); + return NULL; + } + xmlbuf->content = buf->data; + xmlbuf->mobibuffer = buf; + return xmlbuf; +} + +/** + @brief Free XML buffer + + @param[in,out] buf XML buffer + */ +void xmlBufferFree(xmlBufferPtr buf) { + if (buf == NULL) { return; } + if (buf->mobibuffer != NULL) { + mobi_buffer_free(buf->mobibuffer); + } + free(buf); +} + +/** + @brief Initialize TextWriter structure + + @param[in] xmlbuf Initialized xml output buffer + @param[in] compression Unused + @return TextWriter pointer + */ +xmlTextWriterPtr xmlNewTextWriterMemory(xmlBufferPtr xmlbuf, int compression) { + UNUSED(compression); + if (xmlbuf == NULL) { + debug_print("%s", "XML buffer not initialized\n"); + return NULL; + } + xmlTextWriterPtr writer = NULL; + writer = malloc(sizeof(xmlTextWriter)); + if (writer == NULL) { + debug_print("%s", "XML writer allocation failed\n"); + return NULL; + } + writer->xmlbuf = xmlbuf; + writer->states = NULL; + writer->nsname = NULL; + writer->nsvalue = NULL; + writer->indent_enable = false; + writer->indent_next = false; + return writer; +} + +/** + @brief Deallocate TextWriter instance and all its resources + + @param[in,out] writer TextWriter + */ +void xmlFreeTextWriter(xmlTextWriterPtr writer) { + if (writer == NULL) { return; } + if (writer->states != NULL) { + mobi_xml_state_delall(writer->states); + writer->states = NULL; + } + free(writer->nsname); + free(writer->nsvalue); + free(writer); +} + +/** + @brief Start xml document + + Only utf-8 encoding supported. + + @param[in] writer TextWriter + @param[in] version Value of version attribute, "1.0" if NULL + @param[in] encoding Unused, defaults to utf-8 + @param[in] standalone Unused, omitted in declaration + @return TextWriter pointer + */ +int xmlTextWriterStartDocument(xmlTextWriterPtr writer, const char *version, + const char *encoding, const char *standalone) { + UNUSED(encoding); + UNUSED(standalone); + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + if (mobi_xml_level(writer) > 0) { + debug_print("%s\n", "XML document already started"); + return XML_ERROR; + } + MOBI_RET ret = mobi_xml_buffer_addstring(writer, "\n"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief End xml document + + All open elements will be closed. + xmlBuffer will be flushed. + + @param[in] writer TextWriter + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterEndDocument(xmlTextWriterPtr writer) { + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + MOBIXmlState *state = NULL; + while((state = mobi_xml_state_current(writer))) { + switch (state->mode) { + case MOBI_XMLMODE_NAME: + case MOBI_XMLMODE_ATTR: + case MOBI_XMLMODE_TEXT: + xmlTextWriterEndElement(writer); + break; + + default: + break; + } + } + MOBI_RET ret; + if (!writer->indent_enable) { + ret = mobi_xml_buffer_addstring(writer, "\n"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + } + ret = mobi_xml_buffer_flush(writer); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief Start xml element + + @param[in,out] writer TextWriter + @param[in] name Element name + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterStartElement(xmlTextWriterPtr writer, const xmlChar *name) { + if (writer == NULL || name == NULL || *name == '\0') { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + MOBI_RET ret = MOBI_SUCCESS; + MOBIXmlState *state = mobi_xml_state_current(writer); + if (state) { + switch (state->mode) { + case MOBI_XMLMODE_ATTR: + if (xmlTextWriterEndAttribute(writer) == XML_ERROR) { return XML_ERROR; } + /* fallthrough */ + case MOBI_XMLMODE_NAME: + /* TODO: output ns declarations */ + mobi_xml_write_ns(writer); + ret = mobi_xml_buffer_addstring(writer, ">"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + if (writer->indent_enable) { + ret = mobi_xml_buffer_addstring(writer, "\n"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + } + state->mode = MOBI_XMLMODE_TEXT; + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + break; + + default: + break; + } + } + mobi_xml_state_push(writer, (char *) name, MOBI_XMLMODE_NAME); + if (writer->indent_enable) { + ret = mobi_xml_write_indent(writer); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + } + ret = mobi_xml_buffer_addstring(writer, "<"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + ret = mobi_xml_buffer_addstring(writer, (const char *) name); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief End current element + + @param[in] writer TextWriter + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterEndElement(xmlTextWriterPtr writer) { + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + MOBI_RET ret = MOBI_SUCCESS; + MOBIXmlState *state = mobi_xml_state_current(writer); + if (state == NULL) { return XML_ERROR; } + switch (state->mode) { + case MOBI_XMLMODE_ATTR: + if (xmlTextWriterEndAttribute(writer) == XML_ERROR) { return XML_ERROR; } + mobi_xml_state_pop(writer); + /* fallthrough */ + case MOBI_XMLMODE_NAME: + /* output namespace declarations */ + mobi_xml_write_ns(writer); + if (writer->indent_enable) { + writer->indent_next = true; + } + ret = mobi_xml_buffer_addstring(writer, "/>"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + break; + case MOBI_XMLMODE_TEXT: + if (writer->indent_enable && writer->indent_next) { + ret = mobi_xml_write_indent(writer); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + writer->indent_next = true; + } else { + writer->indent_next = true; + } + ret = mobi_xml_buffer_addstring(writer, "name); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + ret = mobi_xml_buffer_addstring(writer, ">"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + break; + + default: + break; + } + if (writer->indent_enable) { + ret = mobi_xml_buffer_addstring(writer, "\n"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + } + mobi_xml_state_pop(writer); + return XML_OK; +} + +/** + @brief Start attribute for current xml element + + @param[in,out] writer TextWriter + @param[in] name Attribute name + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterStartAttribute(xmlTextWriterPtr writer, const xmlChar *name) { + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + if (name == NULL || *name == '\0') { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + MOBI_RET ret = MOBI_SUCCESS; + MOBIXmlState *state = mobi_xml_state_current(writer); + if (state) { + switch (state->mode) { + case MOBI_XMLMODE_ATTR: + if (xmlTextWriterEndAttribute(writer) == XML_ERROR) { return XML_ERROR; } + /* fallthrough */ + case MOBI_XMLMODE_NAME: + ret = mobi_xml_buffer_addstring(writer, " "); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + ret = mobi_xml_buffer_addstring(writer, (const char *) name); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + ret = mobi_xml_buffer_addstring(writer, "=\""); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + state->mode = MOBI_XMLMODE_ATTR; + break; + + default: + return XML_ERROR; + } + } + return XML_OK; +} + +/** + @brief End current attribute + + @param[in,out] writer TextWriter + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterEndAttribute(xmlTextWriterPtr writer) { + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + MOBI_RET ret = MOBI_SUCCESS; + MOBIXmlState *state = mobi_xml_state_current(writer); + if (state) { + switch (state->mode) { + case MOBI_XMLMODE_ATTR: + state->mode = MOBI_XMLMODE_NAME; + ret = mobi_xml_buffer_addstring(writer, "\""); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + break; + + default: + return XML_ERROR; + } + } + return XML_OK; +} + +/** + @brief Write attribute with given name and content + + @param[in,out] writer TextWriter + @param[in] name Attribute name + @param[in] content Attribute content + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterWriteAttribute(xmlTextWriterPtr writer, const xmlChar *name, + const xmlChar * content) { + if (xmlTextWriterStartAttribute(writer, name) == XML_ERROR) { return XML_ERROR; } + if (xmlTextWriterWriteString(writer, content) == XML_ERROR) { return XML_ERROR; } + if (xmlTextWriterEndAttribute(writer) == XML_ERROR) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief Start attribute with namespace support for current xml element + + @param[in,out] writer TextWriter + @param[in] prefix Namespace prefix or NULL + @param[in] name Attribute name + @param[in] namespaceURI Namespace uri or NULL + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterStartAttributeNS(xmlTextWriterPtr writer, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *namespaceURI) { + if (writer == NULL || name == NULL || *name == '\0') { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + if (namespaceURI != NULL) { + char namespace[] = "xmlns"; + if (prefix != NULL) { + size_t length = sizeof(namespace) - 1 + strlen((char *) prefix) + 1; /* add one for ":" */ + char *prefixed = malloc(length + 1); + if (prefixed == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return XML_ERROR; + } + snprintf(prefixed, length + 1, "%s:%s", namespace, prefix); + MOBI_RET ret = mobi_xml_save_ns(writer, prefixed, (char *) namespaceURI); + free(prefixed); + if (ret != MOBI_SUCCESS) { + return XML_ERROR; + } + } else { + MOBI_RET ret = mobi_xml_save_ns(writer, namespace, (char *) namespaceURI); + if (ret != MOBI_SUCCESS) { + return XML_ERROR; + } + } + + } + if (prefix != NULL) { + size_t length = strlen((char *) prefix) + strlen((char *) name) + 1; /* add one for ":" */ + char *prefixed = malloc(length + 1); + if (prefixed == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return XML_ERROR; + } + snprintf(prefixed, length + 1, "%s:%s", prefix, name); + int ret = xmlTextWriterStartAttribute(writer, (xmlChar *)prefixed); + free(prefixed); + if (ret == XML_ERROR) { + return XML_ERROR; + } + } else { + int ret = xmlTextWriterStartAttribute(writer, name); + if (ret == XML_ERROR) { + return XML_ERROR; + } + } + return XML_OK; +} + +/** + @brief Write attribute with namespace support + + @param[in,out] writer TextWriter + @param[in] prefix Namespace prefix or NULL + @param[in] name Attribute name + @param[in] namespaceURI Namespace uri or NULL + @param[in] content Attribute content + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterWriteAttributeNS(xmlTextWriterPtr writer, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *namespaceURI, + const xmlChar *content) { + + if (xmlTextWriterStartAttributeNS(writer, prefix, name, namespaceURI) == XML_ERROR) { return XML_ERROR; } + if (xmlTextWriterWriteString(writer, content) == XML_ERROR) { return XML_ERROR; } + if (xmlTextWriterEndAttribute(writer) == XML_ERROR) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief Start element with namespace support + + @param[in,out] writer TextWriter + @param[in] prefix Namespace prefix or NULL + @param[in] name Element name + @param[in] namespaceURI Namespace uri or NULL + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterStartElementNS(xmlTextWriterPtr writer, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *namespaceURI) { + if (writer == NULL || name == NULL || *name == '\0') { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + if (prefix != NULL) { + size_t length = strlen((char *) prefix) + strlen((char *) name) + 1; + char *prefixed = malloc(length + 1); + if (prefixed == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return XML_ERROR; + } + snprintf(prefixed, length + 1, "%s:%s", prefix, name); + int ret = xmlTextWriterStartElement(writer, (xmlChar *)prefixed); + free(prefixed); + if (ret == XML_ERROR) { return XML_ERROR; } + } else { + if (xmlTextWriterStartElement(writer, name) == XML_ERROR) { return XML_ERROR; } + } + if (namespaceURI != NULL) { + char namespace[] = "xmlns"; + if (prefix != NULL) { + size_t length = sizeof(namespace) - 1 + strlen((char *) prefix) + 1; + char *prefixed = malloc(length + 1); + if (prefixed == NULL) { + debug_print("%s\n", "Memory allocation failed"); + return XML_ERROR; + } + snprintf(prefixed, length + 1, "%s:%s", namespace, prefix); + MOBI_RET ret = mobi_xml_save_ns(writer, prefixed, (char *) namespaceURI); + free(prefixed); + if (ret != MOBI_SUCCESS) { + return XML_ERROR; + } + } else { + MOBI_RET ret = mobi_xml_save_ns(writer, namespace, (char *) namespaceURI); + if (ret != MOBI_SUCCESS) { + return XML_ERROR; + } + } + } + return XML_OK; +} + +/** + @brief Write element with namespace support + + @param[in,out] writer TextWriter + @param[in] prefix Namespace prefix or NULL + @param[in] name Element name + @param[in] namespaceURI Namespace uri or NULL + @param[in] content Element content + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterWriteElementNS(xmlTextWriterPtr writer, const xmlChar *prefix, + const xmlChar *name, const xmlChar *namespaceURI, + const xmlChar *content) { + if (xmlTextWriterStartElementNS(writer, prefix, name, namespaceURI) == XML_ERROR) { return XML_ERROR; } + if (xmlTextWriterWriteString(writer, content) == XML_ERROR) { return XML_ERROR; } + if (xmlTextWriterEndElement(writer) == XML_ERROR) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief Write xml string + + @param[in,out] writer TextWriter + @param[in] content Attribute content + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterWriteString(xmlTextWriterPtr writer, const xmlChar *content) { + if (writer == NULL || content == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + MOBI_RET ret = MOBI_SUCCESS; + MOBI_XML_MODE mode = MOBI_XMLMODE_NONE; + MOBIXmlState *state = mobi_xml_state_current(writer); + if (state != NULL) { + mode = state->mode; + } + switch (mode) { + case MOBI_XMLMODE_NAME: + // output namespace decl + mobi_xml_write_ns(writer); + ret = mobi_xml_buffer_addstring(writer, ">"); + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + state->mode = MOBI_XMLMODE_TEXT; + /* fallthrough */ + case MOBI_XMLMODE_TEXT: + ret = mobi_xml_buffer_addencoded(writer, (const char *) content); + if (writer->indent_enable) { + writer->indent_next = false; + } + break; + case MOBI_XMLMODE_ATTR: + ret = mobi_xml_buffer_addencoded_attr(writer, (const char *) content); + break; + + default: + ret = mobi_xml_buffer_addstring(writer, (const char *) content); + if (writer->indent_enable) { + writer->indent_next = false; + } + break; + } + if (ret != MOBI_SUCCESS) { return XML_ERROR; } + return XML_OK; +} + +/** + @brief Set indentation option + + @param[in,out] writer TextWriter + @param[in] indent Indent output if value greater than zero + @return XML_OK (0) on success, XML_ERROR (-1) on failure + */ +int xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent) { + if (writer == NULL) { + debug_print("%s\n", "XML writer init failed"); + return XML_ERROR; + } + writer->indent_enable = (indent != 0); + writer->indent_next = true; + return XML_OK; +} diff --git a/Charcoal/Charcoal/libmobi-public/src/xmlwriter.h b/Charcoal/Charcoal/libmobi-public/src/xmlwriter.h new file mode 100644 index 0000000..72a2059 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/src/xmlwriter.h @@ -0,0 +1,94 @@ +/** @file xmlwriter.h + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef mobi_minixml_h +#define mobi_minixml_h + +#include +#include "buffer.h" +#include "structure.h" + +#define BAD_CAST (xmlChar *) +#define LIBXML_TEST_VERSION + +#define xmlCleanupParser() + +typedef unsigned char xmlChar; + +/** + @brief Buffer for xml output. + For libxml2 compatibility, it is a wrapper for MOBIBuffer + */ +typedef struct { + xmlChar *content; /**< Points to mobibuffer->data */ + MOBIBuffer *mobibuffer; /**< Dynamic buffer */ +} xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; + +/** + @brief Xml writer states + */ +typedef enum { + MOBI_XMLMODE_NONE = 0, + MOBI_XMLMODE_NAME, + MOBI_XMLMODE_ATTR, + MOBI_XMLMODE_TEXT +} MOBI_XML_MODE; + +/** + @brief Xml writer states list structure + First element in the list is currently processed element. + Last element is root of the document + */ +typedef struct MOBIXmlState { + char *name; /**< Element name */ + MOBI_XML_MODE mode; /**< State mode */ + struct MOBIXmlState *next; /**< Next list item */ +} MOBIXmlState; + +/** + @brief Xml TextWriter structure + */ +typedef struct { + xmlBufferPtr xmlbuf; /**< XML buffer */ + MOBIXmlState *states; /**< TextWriter states list */ + char *nsname; /**< Namespace attribute name */ + char *nsvalue; /**< Namespace attribute value */ + bool indent_enable; /**< Enable indentation */ + bool indent_next; /**< Indentation needed */ +} xmlTextWriter; +typedef xmlTextWriter *xmlTextWriterPtr; + +xmlBufferPtr xmlBufferCreate(void); +void xmlBufferFree(xmlBufferPtr buf); +xmlTextWriterPtr xmlNewTextWriterMemory(xmlBufferPtr xmlbuf, int compression); +void xmlFreeTextWriter(xmlTextWriterPtr writer); +int xmlTextWriterStartDocument(xmlTextWriterPtr writer, const char *version, + const char *encoding, const char *standalone); +int xmlTextWriterEndDocument(xmlTextWriterPtr writer); +int xmlTextWriterStartElement(xmlTextWriterPtr writer, const xmlChar *name); +int xmlTextWriterEndElement(xmlTextWriterPtr writer); +int xmlTextWriterWriteAttribute(xmlTextWriterPtr writer, const xmlChar *name, + const xmlChar *content); +int xmlTextWriterEndAttribute(xmlTextWriterPtr writer); +int xmlTextWriterWriteAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, const xmlChar * name, + const xmlChar * namespaceURI, + const xmlChar * content); +int xmlTextWriterStartElementNS(xmlTextWriterPtr writer, + const xmlChar *prefix, const xmlChar *name, + const xmlChar * namespaceURI); +int xmlTextWriterWriteElementNS(xmlTextWriterPtr writer, const xmlChar *prefix, + const xmlChar *name, const xmlChar *namespaceURI, + const xmlChar *content); +int xmlTextWriterWriteString(xmlTextWriterPtr writer, const xmlChar *content); +int xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent); + +#endif diff --git a/Charcoal/Charcoal/libmobi-public/tools/CMakeLists.txt b/Charcoal/Charcoal/libmobi-public/tools/CMakeLists.txt new file mode 100644 index 0000000..4509cf3 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2022 Bartek Fabiszewski +# http://www.fabiszewski.net +# +# This file is part of libmobi. +# Licensed under LGPL, either version 3, or any later. +# See + +include_directories(${LIBMOBI_SOURCE_DIR}/src) + +add_library(common OBJECT common.c) + +add_executable(mobitool mobitool.c) +target_link_libraries(mobitool PUBLIC mobi) +target_link_libraries(mobitool PRIVATE common) +add_executable(mobimeta mobimeta.c) +target_link_libraries(mobimeta PUBLIC mobi) +target_link_libraries(mobimeta PRIVATE common) +add_executable(mobidrm mobidrm.c) +target_link_libraries(mobidrm PUBLIC mobi) +target_link_libraries(mobidrm PRIVATE common) + +if(USE_XMLWRITER) +# miniz.c zip functions are needed for epub creation + set(zip_SOURCES + ${LIBMOBI_SOURCE_DIR}/src/miniz.c + ${LIBMOBI_SOURCE_DIR}/src/miniz.h + ) + add_library(zip OBJECT ${zip_SOURCES}) + target_compile_definitions(zip PRIVATE + MINIZ_NO_ZLIB_COMPATIBLE_NAMES + _POSIX_C_SOURCE=200112L) + target_link_libraries(mobitool PRIVATE zip) + target_link_libraries(mobimeta PRIVATE zip) + if (TOOLS_STATIC AND USE_MINIZ) + target_link_options(mobitool PRIVATE "-Wl,--allow-multiple-definition") + endif (TOOLS_STATIC AND USE_MINIZ) +endif(USE_XMLWRITER) diff --git a/Charcoal/Charcoal/libmobi-public/tools/Makefile.am b/Charcoal/Charcoal/libmobi-public/tools/Makefile.am new file mode 100644 index 0000000..2d529e1 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/Makefile.am @@ -0,0 +1,51 @@ +# tools + +# this lists the binaries to produce, the (non-PHONY, binary) targets in +# the previous manual Makefile +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src + +bin_PROGRAMS = mobitool mobimeta +man_MANS = mobitool.1 mobimeta.1 + +noinst_LIBRARIES = libcommon.a +libcommon_a_SOURCES = common.c common.h + +if USE_INTERNAL_GETOPT +libcommon_a_SOURCES += win32/getopt.c win32/getopt.h +endif + +mobitool_SOURCES = mobitool.c +mobitool_DEPENDENCIES = $(top_builddir)/src/libmobi.la libcommon.a +mobitool_LDADD = libcommon.a $(top_builddir)/src/libmobi.la +mobitool_CFLAGS = $(ISO99_SOURCE) $(DEBUG_CFLAGS) -D_POSIX_C_SOURCE=200112L +mobitool_LDFLAGS = $(TOOLS_STATIC) + +if USE_XMLWRITER +# miniz.c zip functions are needed for epub creation +noinst_LIBRARIES += libminiz.a +libminiz_a_SOURCES = ../src/miniz.c ../src/miniz.h +libminiz_a_CFLAGS = $(MINIZ_CFLAGS) -DMINIZ_NO_ZLIB_COMPATIBLE_NAMES +mobitool_DEPENDENCIES += libminiz.a +mobitool_LDADD += libminiz.a +if USE_STATIC +if USE_MINIZ +mobitool_LDFLAGS += $(MOBI_ALLOW_MULTIPLE) +endif +endif +endif + +mobimeta_SOURCES = mobimeta.c +mobimeta_DEPENDENCIES = $(top_builddir)/src/libmobi.la libcommon.a +mobimeta_LDADD = libcommon.a $(top_builddir)/src/libmobi.la +mobimeta_CFLAGS = $(ISO99_SOURCE) $(DEBUG_CFLAGS) -D_POSIX_C_SOURCE=200112L +mobimeta_LDFLAGS = $(TOOLS_STATIC) + +if USE_ENCRYPTION +bin_PROGRAMS += mobidrm +man_MANS += mobidrm.1 +mobidrm_SOURCES = mobidrm.c +mobidrm_DEPENDENCIES = $(top_builddir)/src/libmobi.la libcommon.a +mobidrm_LDADD = libcommon.a $(top_builddir)/src/libmobi.la +mobidrm_CFLAGS = $(ISO99_SOURCE) $(DEBUG_CFLAGS) -D_POSIX_C_SOURCE=200112L +mobidrm_LDFLAGS = $(TOOLS_STATIC) +endif diff --git a/Charcoal/Charcoal/libmobi-public/tools/README.md b/Charcoal/Charcoal/libmobi-public/tools/README.md new file mode 100644 index 0000000..6f89e68 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/README.md @@ -0,0 +1,51 @@ +## mobitool + usage: /Users/baf/src/libmobi/tools/.libs/mobitool [-cdehimrstuvx7] [-o dir] [-p pid] [-P serial] filename + without arguments prints document metadata and exits + -c dump cover + -d dump rawml text record + -e create EPUB file (with -s will dump EPUB source) + -h show this usage summary and exit + -i print detailed metadata + -m print records metadata + -o dir save output to dir folder + -p pid set pid for decryption + -P serial set device serial for decryption + -r dump raw records + -s dump recreated source files + -t split hybrid file into two parts + -u show rusage + -v show version and exit + -x extract conversion source and log (if present) + -7 parse KF7 part of hybrid file (by default KF8 part is parsed) + +## mobimeta + usage: mobimeta [-a | -s meta=value[,meta=value,...]] [-d meta[,meta,...]] [-p pid] [-P serial] [-hv] filein [fileout] + without arguments prints document metadata and exits + -a ? list valid meta named keys + -a meta=value add metadata + -d meta delete metadata + -s meta=value set metadata + -p pid set pid for decryption + -P serial set device serial for decryption + -h show this usage summary and exit + -v show version and exit + +## mobidrm + usage: mobidrm [-d | -e] [-hv] [-p pid] [-f date] [-t date] [-s serial] [-o dir] filename + without arguments prints document metadata and exits + + Decrypt options: + -d decrypt (required) + -p pid set decryption pid (may be specified multiple times) + -s serial set device serial (may be specified multiple times) + + Encrypt options: + -e encrypt (required) + -s serial set device serial (may be specified multiple times) + -f date set validity period from date (yyyy-mm-dd) when encrypting (inclusive) + -t date set validity period to date (yyyy-mm-dd) when encrypting (inclusive) + + Common options: + -o dir save output to dir folder + -h show this usage summary and exit + -v show version and exit diff --git a/Charcoal/Charcoal/libmobi-public/tools/common.c b/Charcoal/Charcoal/libmobi-public/tools/common.c new file mode 100644 index 0000000..409a4b4 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/common.c @@ -0,0 +1,621 @@ +/** @file common.c + * + * @brief common tools functions + * + * @example common.c + * Common functions for tools + * + * Copyright (c) 2016 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include "common.h" + +#ifdef _WIN32 +# include +# define mkdir(path,flags) _mkdir(path) +const char separator = '\\'; +#else +const char separator = '/'; +#endif +bool outdir_opt = false; +char outdir[FILENAME_MAX]; + +#define UNUSED(x) (void)(x) + +#ifndef min +# define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/** + @brief Messages for libmobi return codes + For reference see enum MOBI_RET in mobi.h + */ +const char *libmobi_messages[] = { + "Success", + "Generic error", + "Wrong function parameter", + "Corrupted data", + "File not found", + "Document is encrypted", + "Unsupported document format", + "Memory allocation error", + "Initialization error", + "Buffer error", + "XML error", + "Invalid DRM pid", + "DRM key not found", + "DRM support not included", + "Write failed", + "DRM expired" +}; + +#define LIBMOBI_MSG_COUNT ARRAYSIZE(libmobi_messages) + +/** + @brief Return message for given libmobi return code + @param[in] ret Libmobi return code + @return Message string + */ +const char * libmobi_msg(const MOBI_RET ret) { + size_t index = ret; + if (index < LIBMOBI_MSG_COUNT) { + return libmobi_messages[index]; + } + return "Unknown error"; +} + +/** + @brief Parse file name into file path and base name. + Dirname or basename can be skipped by setting to null. + @param[in] fullpath Full file path + @param[in,out] dirname Will be set to full dirname + @param[in,out] basename Will be set to file basename + @param[in] buf_len Size of each ouput buffer: dirname and basename + */ +void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len) { + if (buf_len == 0) { + return; + } + char *p = strrchr(fullpath, separator); + if (p) { + p += 1; + if (dirname) { + size_t dirlen = min(buf_len - 1, (size_t) (p - fullpath)); + strncpy(dirname, fullpath, dirlen); + dirname[dirlen] = '\0'; + } + if (basename) { + strncpy(basename, p, buf_len - 1); + basename[buf_len - 1] = '\0'; + } + } + else { + if (dirname) { + dirname[0] = '\0'; + } + if (basename) { + strncpy(basename, fullpath, buf_len - 1); + basename[buf_len - 1] = '\0'; + } + } + if (basename) { + p = strrchr(basename, '.'); + if (p) { + *p = '\0'; + } + } +} + +/** + @brief Make directory + @param[in] path Path + @return SUCCESS or ERROR + */ +int make_directory(const char *path) { + errno = 0; + if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST) { + int errsv = errno; + printf("Creating directory \"%s\" failed (%s)\n", path, strerror(errsv)); + return ERROR; + } + return SUCCESS; +} + +/** + @brief Create subfolder in directory + @param[in,out] newdir Path to created subfolder + @param[in] buf_len Buffer size fo created subfolder + @param[in] parent_dir Directory path + @param[in] subdir_name Subfolder name + @return SUCCESS or ERROR + */ +int create_subdir(char *newdir, const size_t buf_len, const char *parent_dir, const char *subdir_name) { + int n = snprintf(newdir, buf_len, "%s%c%s", parent_dir, separator, subdir_name); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= buf_len) { + printf("File name too long: %s\n", newdir); + return ERROR; + } + return make_directory(newdir); +} + +/** + @brief Open file descriptor and write buffer to it + @param[in] buffer Buffer + @param[in] len Buffer length + @param[in] path File path + @return SUCCESS or ERROR + */ +int write_file(const unsigned char *buffer, const size_t len, const char *path) { + errno = 0; + FILE *file = fopen(path, "wb"); + if (file == NULL) { + int errsv = errno; + printf("Could not open file for writing: %s (%s)\n", path, strerror(errsv)); + return ERROR; + } + size_t n = fwrite(buffer, 1, len, file); + if (n != len) { + int errsv = errno; + printf("Error writing to file: %s (%s)\n", path, strerror(errsv)); + fclose(file); + return ERROR; + } + fclose(file); + return SUCCESS; +} + +/** + @brief Write content to file in directory + @param[in] dir Directory path + @param[in] name File name + @param[in] buffer Buffer + @param[in] len Buffer length + @return SUCCESS or ERROR + */ +int write_to_dir(const char *dir, const char *name, const unsigned char *buffer, const size_t len) { + char path[FILENAME_MAX]; + int n = snprintf(path, sizeof(path), "%s%c%s", dir, separator, name); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(path)) { + printf("File name too long\n"); + return ERROR; + } + return write_file(buffer, len, path); +} + +/** + @brief Check whether given path exists and is a directory + @param[in] path Path to be tested + @return True if directory exists, false otherwise + */ +bool dir_exists(const char *path) { + struct stat sb; + if (stat(path, &sb) != 0) { + int errsv = errno; + printf("Path \"%s\" is not accessible (%s)\n", path, strerror(errsv)); + return false; + } + if (!S_ISDIR(sb.st_mode)) { + printf("Path \"%s\" is not a directory\n", path); + return false; + } + return true; +} + +/** + @brief Make sure we use consistent separators on Windows builds + @param[in,out] path Path to be fixed + */ +void normalize_path(char *path) { +#ifdef _WIN32 + if (path != NULL) { + for (size_t i = 0; i <= strlen(path); i++) { + if (path[i] == '/') { + path[i] = separator; + } + } + } +#else + UNUSED(path); +#endif +} + + +/** + @brief Print summary meta information + @param[in] m MOBIData structure + */ +void print_summary(const MOBIData *m) { + char *title = mobi_meta_get_title(m); + if (title) { + printf("Title: %s\n", title); + free(title); + } + char *author = mobi_meta_get_author(m); + if (author) { + printf("Author: %s\n", author); + free(author); + } + char *contributor = mobi_meta_get_contributor(m); + uint32_t major = 0, minor = 0, build = 0; + bool is_calibre = false; + if (contributor) { + const char *calibre_contributor = "calibre ("; + if (strncmp(contributor, calibre_contributor, strlen(calibre_contributor)) == 0) { + is_calibre = true; + sscanf(contributor, "calibre (%u.%u.%u)", &major, &minor, &build); + } else { + printf("Contributor: %s\n", contributor); + } + free(contributor); + } + char *subject = mobi_meta_get_subject(m); + if (subject) { + printf("Subject: %s\n", subject); + free(subject); + } + char *publisher = mobi_meta_get_publisher(m); + if (publisher) { + printf("Publisher: %s\n", publisher); + free(publisher); + } + char *date = mobi_meta_get_publishdate(m); + if (date) { + printf("Publishing date: %s\n", date); + free(date); + } + char *description = mobi_meta_get_description(m); + if (description) { + printf("Description: %s\n", description); + free(description); + } + char *review = mobi_meta_get_review(m); + if (review) { + printf("Review: %s\n", review); + free(review); + } + char *imprint = mobi_meta_get_imprint(m); + if (imprint) { + printf("Imprint: %s\n", imprint); + free(imprint); + } + char *copyright = mobi_meta_get_copyright(m); + if (copyright) { + printf("Copyright: %s\n", copyright); + free(copyright); + } + char *isbn = mobi_meta_get_isbn(m); + if (isbn) { + printf("ISBN: %s\n", isbn); + free(isbn); + } + char *asin = mobi_meta_get_asin(m); + if (asin) { + printf("ASIN: %s\n", asin); + free(asin); + } + char *language = mobi_meta_get_language(m); + if (language) { + printf("Language: %s", language); + free(language); + if (m->mh && m->mh->text_encoding) { + uint32_t encoding = *m->mh->text_encoding; + if (encoding == MOBI_CP1252) { + printf(" (cp1252)"); + } else if (encoding == MOBI_UTF8) { + printf(" (utf8)"); + } + } + printf("\n"); + } + if (mobi_is_dictionary(m)) { + printf("Dictionary"); + if (m->mh && m->mh->dict_input_lang && m->mh->dict_output_lang && + *m->mh->dict_input_lang && *m->mh->dict_output_lang) { + const char *locale_in = mobi_get_locale_string(*m->mh->dict_input_lang); + const char *locale_out = mobi_get_locale_string(*m->mh->dict_output_lang); + printf(": %s => %s", locale_in ? locale_in : "unknown", locale_out ? locale_out : "unknown"); + } + printf("\n"); + } + printf("__\n"); + if (strcmp(m->ph->type, "TEXt") == 0) { + if (strcmp(m->ph->creator, "TlDc") == 0) { + printf("TealDoc\n"); + } else { + printf("PalmDoc\n"); + } + } else { + printf("Mobi version: %zu", mobi_get_fileversion(m)); + if (mobi_is_hybrid(m)) { + size_t version = mobi_get_fileversion(m->next); + if (version != MOBI_NOTSET) { + printf(" (hybrid with version %zu)", version); + } + } + printf("\n"); + } + if (mobi_is_replica(m)) { + printf("Print Replica\n"); + } + if (mobi_is_encrypted(m)) { + printf("Document is encrypted\n"); + } + if (is_calibre) { + printf("Creator software: calibre %u.%u.%u\n", major, minor, build); + } else { + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORSOFT); + if (exth) { + printf("Creator software: "); + uint32_t creator = mobi_decode_exthvalue(exth->data, exth->size); + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORMAJOR); + if (exth) { + major = mobi_decode_exthvalue(exth->data, exth->size); + } + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORMINOR); + if (exth) { + minor = mobi_decode_exthvalue(exth->data, exth->size); + } + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORBUILD); + if (exth) { + build = mobi_decode_exthvalue(exth->data, exth->size); + } + exth = mobi_get_exthrecord_by_tag(m, EXTH_CREATORBUILDREV); + if (major == 2 && minor == 9 && build == 0 && exth) { + char *rev = mobi_decode_exthstring(m, exth->data, exth->size); + if (rev) { + if (strcmp(rev, "0730-890adc2") == 0) { + is_calibre = true; + } + free(rev); + } + } + switch (creator) { + case 0: + printf("mobipocket reader %u.%u.%u", major, minor, build); + break; + case 1: + case 101: + printf("mobigen %u.%u.%u", major, minor, build); + break; + case 2: + printf("mobipocket creator %u.%u.%u", major, minor, build); + break; + case 200: + printf("kindlegen %u.%u.%u (windows)", major, minor, build); + if (is_calibre) { + printf(" or calibre"); + } + break; + case 201: + printf("kindlegen %u.%u.%u (linux)", major, minor, build); + if ((major == 1 && minor == 2 && build == 33307) || + (major == 2 && minor == 0 && build == 101) || + is_calibre) { + printf(" or calibre"); + } + break; + case 202: + printf("kindlegen %u.%u.%u (mac)", major, minor, build); + if (is_calibre) { + printf(" or calibre"); + } + break; + default: + printf("unknown"); + break; + } + printf("\n"); + } + } +} + +/** + @brief Print all loaded EXTH record tags + @param[in] m MOBIData structure + */ +void print_exth(const MOBIData *m) { + if (m->eh == NULL) { + return; + } + /* Linked list of MOBIExthHeader structures holds EXTH records */ + const MOBIExthHeader *curr = m->eh; + if (curr != NULL) { + printf("\nEXTH records:\n"); + } + uint32_t val32; + while (curr != NULL) { + /* check if it is a known tag and get some more info if it is */ + MOBIExthMeta tag = mobi_get_exthtagmeta_by_tag(curr->tag); + if (tag.tag == 0) { + /* unknown tag */ + /* try to print the record both as string and numeric value */ + char *str = malloc(curr->size + 1); + if (!str) { + printf("Memory allocation failed\n"); + exit(1); + } + unsigned i = 0; + unsigned char *p = curr->data; + while (i < curr->size && isprint(*p)) { + str[i] = (char)*p++; + i++; + } + str[i] = '\0'; + val32 = mobi_decode_exthvalue(curr->data, curr->size); + printf("Unknown (%i): %s (%u)\n", curr->tag, str, val32); + free(str); + } else { + /* known tag */ + size_t size = curr->size; + unsigned char *data = curr->data; + switch (tag.type) { + /* numeric */ + case EXTH_NUMERIC: + val32 = mobi_decode_exthvalue(data, size); + printf("%s (%i): %u\n", tag.name, tag.tag, val32); + break; + /* string */ + case EXTH_STRING: + { + char *exth_string = mobi_decode_exthstring(m, data, size); + if (exth_string) { + printf("%s (%i): %s\n", tag.name, tag.tag, exth_string); + free(exth_string); + } + break; + } + /* binary */ + case EXTH_BINARY: + { + unsigned i = 0; + const size_t str_len = 2 * size + 1; + char *str = malloc(str_len); + if (!str) { + printf("Memory allocation failed\n"); + exit(1); + } + str[0] = '\0'; + while (size) { + uint8_t val8 = *data++; + snprintf(&str[i], str_len - i, "%02x", val8); + i += 2; + size--; + } + printf("%s (%i): 0x%s\n", tag.name, tag.tag, str); + free(str); + break; + } + default: + break; + } + } + curr = curr->next; + } +} + +/** + @brief Set PID for decryption + @param[in,out] m MOBIData structure + @param[in] pid Serial number + @return SUCCESS or error code + */ +int set_decryption_pid(MOBIData *m, const char *pid) { + printf("\nVerifying PID %s...", pid); + MOBI_RET mobi_ret = mobi_drm_setkey(m, pid); + if (mobi_ret != MOBI_SUCCESS) { + printf("failed (%s)\n", libmobi_msg(mobi_ret)); + return (int) mobi_ret; + } + printf("ok\n"); + return SUCCESS; +} + +/** + @brief Set device serial number for decryption + @param[in,out] m MOBIData structure + @param[in] serial Serial number + @return SUCCESS or error code + */ +int set_decryption_serial(MOBIData *m, const char *serial) { + printf("\nVerifying serial %s... ", serial); + MOBI_RET mobi_ret = mobi_drm_setkey_serial(m, serial); + if (mobi_ret != MOBI_SUCCESS) { + printf("failed (%s)\n", libmobi_msg(mobi_ret)); + return (int) mobi_ret; + } + printf("ok\n"); + return SUCCESS; +} + +/** + @brief Set key for decryption. Use user supplied pid or device serial number + @param[in,out] m MOBIData structure + @param[in] serial Serial number + @param[in] pid Pid + @return SUCCESS or error code + */ +int set_decryption_key(MOBIData *m, const char *serial, const char *pid) { + + if (!pid && !serial) { + return SUCCESS; + } + if (!mobi_is_encrypted(m)) { + printf("\nDocument is not encrypted, ignoring PID/serial\n"); + return SUCCESS; + } + if (m->rh && m->rh->encryption_type == MOBI_ENCRYPTION_V1) { + printf("\nEncryption type 1, ignoring PID/serial\n"); + return SUCCESS; + } + int ret = SUCCESS; + if (pid && (ret = set_decryption_pid(m, pid)) == SUCCESS) { + return SUCCESS; + } + if (serial) { + ret = set_decryption_serial(m, serial); + } + return ret; +} + +/** + @brief Save mobi file + + @param[in,out] m MOBIData struicture + @param[in] fullpath Full file path + @param[in] suffix Suffix appended to file name + @return SUCCESS or ERROR + */ +int save_mobi(MOBIData *m, const char *fullpath, const char *suffix) { + char outfile[FILENAME_MAX]; + char basename[FILENAME_MAX]; + char dirname[FILENAME_MAX]; + split_fullpath(fullpath, dirname, basename, FILENAME_MAX); + const char *ext = (mobi_get_fileversion(m) >= 8) ? "azw3" : "mobi"; + int n; + if (outdir_opt) { + n = snprintf(outfile, sizeof(outfile), "%s%s-%s.%s", outdir, basename, suffix, ext); + } else { + n = snprintf(outfile, sizeof(outfile), "%s%s-%s.%s", dirname, basename, suffix, ext); + } + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(outfile)) { + printf("File name too long\n"); + return ERROR; + } + + /* write */ + printf("Saving %s...\n", outfile); + FILE *file_out = fopen(outfile, "wb"); + if (file_out == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", outfile, strerror(errsv)); + return ERROR; + } + MOBI_RET mobi_ret = mobi_write_file(file_out, m); + fclose(file_out); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error writing file (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + return SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/tools/common.h b/Charcoal/Charcoal/libmobi-public/tools/common.h new file mode 100644 index 0000000..77115c2 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/common.h @@ -0,0 +1,78 @@ +/** @file common.h + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef common_h +#define common_h + +#include +#include + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif + +#ifdef HAVE_GETOPT +# include +#else +# include "win32/getopt.h" +#endif + +/* return codes */ +#define ERROR 1 +#define SUCCESS 0 + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#if defined(__clang__) +# define COMPILER "clang " __VERSION__ +#elif defined(__SUNPRO_C) +# define COMPILER "suncc " STR(__SUNPRO_C) +#elif defined(__GNUC__) +# if (defined(__MINGW32__) || defined(__MINGW64__)) +# define COMPILER "gcc (MinGW) " __VERSION__ +# else +# define COMPILER "gcc " __VERSION__ +# endif +#elif defined(_MSC_VER) +# define COMPILER "MSVC++ " STR(_MSC_VER) +#else +# define COMPILER "unknown" +#endif + +#if !defined S_ISDIR && defined S_IFDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISDIR +# error "At least one of S_ISDIR or S_IFDIR macros is required" +#endif + +#define FULLNAME_MAX 1024 + +extern const char separator; +extern bool outdir_opt; +extern char outdir[FILENAME_MAX]; + +const char * libmobi_msg(const MOBI_RET ret); +void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len); +int make_directory(const char *path); +int create_subdir(char *newdir, const size_t buf_len, const char *parent_dir, const char *subdir_name); +int write_file(const unsigned char *buffer, const size_t len, const char *path); +int write_to_dir(const char *dir, const char *name, const unsigned char *buffer, const size_t len); +bool dir_exists(const char *path); +void normalize_path(char *path); +void print_summary(const MOBIData *m); +void print_exth(const MOBIData *m); +int set_decryption_key(MOBIData *m, const char *serial, const char *pid); +int set_decryption_pid(MOBIData *m, const char *pid); +int set_decryption_serial(MOBIData *m, const char *serial); +int save_mobi(MOBIData *m, const char *fullpath, const char *suffix); +#endif /* common_h */ diff --git a/Charcoal/Charcoal/libmobi-public/tools/mobidrm.1.in b/Charcoal/Charcoal/libmobi-public/tools/mobidrm.1.in new file mode 100644 index 0000000..8cee764 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/mobidrm.1.in @@ -0,0 +1,124 @@ +.Dd February 16, 2022 +.Dt mobidrm 1 URM +.Os Unix +.Sh NAME +.Nm mobidrm +.Nd Utility for decryption and encryption of MOBI format ebook files. +.Sh SYNOPSIS +.Nm +.Fl d +.Op Fl o Ar dir +.Op Fl p Ar pid +.Op Fl s Ar serial +.Ar file +.Nm +.Fl e +.Op Fl o Ar dir +.Op Fl s Ar serial +.Op Fl f Ar date +.Op Fl t Ar date +.Ar file +.Nm +.Op Fl hv +.Sh DESCRIPTION +The program encrypts or decrypts MOBI files with DRM schemes used on eInk devices. It is powered by +.Nm libmobi +library. +.Pp +It may encrypt documents targeting particular device by using its serial number or applying generic DRM scheme targeting all supported readers. +.Pp +Optionally encryption may be valid only during chosen period. Kindles require both start and end date to be set. +This tool allows to specify only one date (start or end). +In such case the other date will be automatically set to respectively lowest (1970-01-01) or largest (10136-02-16) valid value. +.Pp +In case of hybrid files mobidrm separately encrypts both enclosed parts and produces two files: mobi for legacy format and azw3 for KF8 format. +.Pp +The program also decrypts documents. One must supply device serial number or document PID if DRM was applied for specific device. +.Pp +Invoked without arguments prints usage summary and exits. +.Pp +A list of flags and their descriptions. +.Pp +\fBDecryption flags\fR: +.Pp +.Bl -tag -width -indent +.It Fl d +Decrypt. This flag must be set in order to decrypt document. +.It Fl p Ar pid +Set optional decryption +.Ar pid +(may be specified multiple times). +.It Fl s Ar serial +Set optional device +.Ar serial +number (may be specified multiple times). +.El +.Pp +\fBEncryption flags\fR: +.Bl -tag -width -indent +.It Fl e +Encrypt. This flag must be set in order to encrypt document. +.It Fl f Ar date +Set optional validity period \fBfrom\fR +.Ar date +formatted as yyyy-mm-dd. Document will not be valid before this date. +.It Fl s Ar serial +Set optional device +.Ar serial +number. If not set document will be encrypted with generic reader key. This flag may be specified +multiple times to target multiple devices. +.It Fl t Ar date +Set optional validity period \fBto\fR +.Ar date +formatted as yyyy-mm-dd. Document will expire after this date. +.El +.Pp +\fBCommon flags\fR: +.Bl -tag -width -indent +.It Fl o Ar dir +Save output to +.Ar dir +folder. +.It Fl h +Show usage summary and exit. +.It Fl v +Show version and exit. +.El +.Pp +.Sh EXAMPLES +The following command decrypts document using given serial number. Decrypted output will be saved to /tmp folder. +.Pp +.Dl % mobidrm -d -s B001XXXXXXXXXXXX -o /tmp example.mobi +.Pp +The following command decrypts document trying multiple PIDs. +.Pp +.Dl % mobidrm -d -p XXXXXXXXX1 -p XXXXXXXXX2 example.mobi +.Pp +The following command encrypts document targeting two devices using their serial numbers. Document will be readable only on those devices. +.Pp +.Dl % mobidrm -e -s B001XXXXXXXXXX01 -s B001XXXXXXXXXX02 example.mobi +.Pp +The following command encrypts document for device wth given serial number. Document will only be valid within given period (inclusive). +.Pp +.Dl % mobidrm -e -s B001XXXXXXXXXX01 -f 2021-01-01 -t 2021-01-31 example.mobi +.Sh RETURN VALUES +The +.Nm +utility returns 0 on success, 1 on error. +.Sh COPYRIGHT +Copyright (C) 2021-2022 Bartek Fabiszewski. +.Pp +Released under LGPL version 3 or any later (same as +.Nm libmobi Ns +). +.Sh WEB SITE +Visit http://www.fabiszewski.net for details. +.Sh DIAGNOSTICS +For diagnostics +.Nm libmobi +must be configured with +.Fl Fl enable-debug +option. +.Sh SEE ALSO +.Xr mobimeta 1 +.Xr mobitool 1 diff --git a/Charcoal/Charcoal/libmobi-public/tools/mobidrm.c b/Charcoal/Charcoal/libmobi-public/tools/mobidrm.c new file mode 100644 index 0000000..971334a --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/mobidrm.c @@ -0,0 +1,488 @@ +/** @file mobidrm.c + * + * @brief mobidrm + * + * Copyright (c) 2021 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define VOUCHERS_COUNT_MAX 20 + +/* command line options */ +bool decrypt_opt = false; +bool encrypt_opt = false; +bool expiry_opt = false; + +/* options values */ +char *pid[VOUCHERS_COUNT_MAX]; +char *serial[VOUCHERS_COUNT_MAX]; +size_t serial_count = 0; +size_t pid_count = 0; +time_t valid_from = -1; +time_t valid_to = -1; + + +/** + @brief Print usage info + @param[in] progname Executed program name + */ +static void print_usage(const char *progname) { + printf("usage: %s [-d | -e] [-hv] [-p pid] [-f date] [-t date] [-s serial] [-o dir] filename\n", progname); + printf(" without arguments prints document metadata and exits\n\n"); + + printf(" Decrypt options:\n"); + printf(" -d decrypt (required)\n"); + printf(" -p pid set decryption pid (may be specified multiple times)\n"); + printf(" -s serial set device serial (may be specified multiple times)\n\n"); + + printf(" Encrypt options:\n"); + printf(" -e encrypt (required)\n"); + printf(" -s serial set device serial (may be specified multiple times)\n"); + printf(" -f date set validity period from date (yyyy-mm-dd) when encrypting (inclusive)\n"); + printf(" -t date set validity period to date (yyyy-mm-dd) when encrypting (inclusive)\n\n"); + + printf(" Common options:\n"); + printf(" -o dir save output to dir folder\n"); + printf(" -h show this usage summary and exit\n"); + printf(" -v show version and exit\n"); +} + +/** + @brief Applies DRM + + @param[in,out] m MOBIData structure + @param[in] use_kf8 In case of hybrid file process KF8 part if true, the other part otherwise + @return SUCCESS or ERROR + */ +static int do_encrypt(MOBIData *m, bool use_kf8) { + + MOBI_RET mobi_ret; + + if (mobi_is_hybrid(m)) { + mobi_ret = mobi_remove_hybrid_part(m, !use_kf8); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error removing hybrid part (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + printf("\nProcessing file version %zu from hybrid file\n", mobi_get_fileversion(m)); + } + + MOBIExthTag *tags = NULL; + MOBIExthTag amazonkeys[] = { EXTH_WATERMARK, EXTH_TTSDISABLE, EXTH_CLIPPINGLIMIT, EXTH_READFORFREE, EXTH_RENTAL, EXTH_UNK407 }; + MOBIExthTag tamperkeys[ARRAYSIZE(amazonkeys)] = { 0 }; + size_t tags_count = 0; + + if (mobi_get_fileversion(m) >= 4 && m->eh) { + // EXTH tamperproof keys are required with encryption scheme 2 in mobi version 8 + // and are supported since version 4. + // Amazon software by default includes tags: 208, 404, 401, 405, 406, 407 in DRM scheme. + // Any change in tags that are included invalidates DRM. + // You can secure any tag you want, we just add dummy watermark (208) if it is not already present in file + // to satisfy requirements. + if (mobi_get_exthrecord_by_tag(m, EXTH_WATERMARK) == NULL) { + char watermark[] = "aHR0cHM6Ly9naXRodWIuY29tL2JmYWJpc3pld3NraS9saWJtb2Jp"; + mobi_add_exthrecord(m, EXTH_WATERMARK, (uint32_t) strlen(watermark), watermark); + } + tamperkeys[0] = amazonkeys[0]; + tags_count++; + // If any of the Amazon default tags is present in file, secure it too. + // You can also add any of them with mobimeta before running mobidrm. + for (size_t i = 1; i < ARRAYSIZE(amazonkeys); i++) { + // if exth record exists in mobi file + if (mobi_get_exthrecord_by_tag(m, amazonkeys[i]) != NULL) { + // add it tamperproof keys + tamperkeys[tags_count++] = amazonkeys[i]; + } + } + + tags = tamperkeys; + } + + for (size_t i = 0; i < serial_count; i++) { + mobi_ret = mobi_drm_addvoucher(m, serial[i], valid_from, valid_to, tags, tags_count); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error adding encryption voucher (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + } + if (serial_count == 0) { + mobi_ret = mobi_drm_addvoucher(m, NULL, valid_from, valid_to, tags, tags_count); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error adding encryption voucher (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + } + + mobi_ret = mobi_drm_encrypt(m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error encrypting document (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + + printf("Encrypting with encryption type %u\n", m->rh->encryption_type); + if (m->rh->encryption_type == MOBI_ENCRYPTION_V1 && serial_count) { + printf("Warning! Encryption with device serial number is not supported with this encryption scheme. Skipping serial...\n"); + } + if (valid_from != -1) { + printf("Drm validity period from %s", ctime(&valid_from)); + } + if (valid_to != -1) { + printf("Drm validity period to %s", ctime(&valid_to)); + } + return SUCCESS; +} + +/** + @brief Removes DRM + + @param[in,out] m MOBIData structure + @return SUCCESS or ERROR + */ +static int do_decrypt(MOBIData *m) { + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_RENTAL); + if (exth) { + uint32_t is_rental = mobi_decode_exthvalue(exth->data, exth->size); + if (is_rental) { + printf("Can't remove DRM from rented documents\n"); + return ERROR; + } + } + uint16_t encryption_type = m->rh->encryption_type; + printf("Removing encryption type %u\n", encryption_type); + bool has_key = false; + if (pid_count) { + for (size_t i = 0; i < pid_count; i++) { + if (set_decryption_pid(m, pid[i]) == SUCCESS) { + has_key = true; + break; + } + } + } + if (!has_key && serial_count) { + for (size_t i = 0; i < serial_count; i++) { + if (set_decryption_serial(m, serial[i]) == SUCCESS) { + break; + } + } + } + MOBI_RET mobi_ret = mobi_drm_decrypt(m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error encrypting document (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + + if (encryption_type == MOBI_ENCRYPTION_V2) { + // remove EXTH records that impose restrictions or are DRM related + MOBIExthTag drmkeys[] = { EXTH_TAMPERKEYS, EXTH_WATERMARK, EXTH_TTSDISABLE, EXTH_CLIPPINGLIMIT, EXTH_READFORFREE, EXTH_RENTAL, EXTH_UNK407 }; + for (size_t i = 0; i < ARRAYSIZE(drmkeys); i++) { + mobi_ret = mobi_delete_exthrecord_by_tag(m, drmkeys[i]); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error removing EXTH record %u\n", drmkeys[i]); + return ERROR; + } + } + } + return SUCCESS; +} + +/** + @brief Main routine that calls optional subroutines + + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int loadfilename(const char *fullpath) { + + static int run_count = 0; + run_count++; + + bool use_kf8 = run_count == 1 ? false : true; + + /* Initialize main MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Memory allocation failed\n"); + return ERROR; + } + + errno = 0; + FILE *file = fopen(fullpath, "rb"); + if (file == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", fullpath, strerror(errsv)); + mobi_free(m); + return ERROR; + } + + /* MOBIData structure will be filled with loaded document data and metadata */ + MOBI_RET mobi_ret = mobi_load_file(m, file); + fclose(file); + + if (mobi_ret != MOBI_SUCCESS) { + printf("Error while loading document (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + if (run_count == 1) { + print_summary(m); + } + + // save is hybrid result here, as file may be modified later + bool is_hybrid = mobi_is_hybrid(m); + + int ret = SUCCESS; + const char *suffix; + if (encrypt_opt) { + // encrypt + if (mobi_is_encrypted(m)) { + mobi_free(m); + printf("Document is already encrypted\n"); + return ERROR; + } + ret = do_encrypt(m, use_kf8); + if (ret != SUCCESS) { + mobi_free(m); + return ERROR; + } + suffix = "encrypted"; + } else { + // decrypt + if (!mobi_is_encrypted(m)) { + mobi_free(m); + printf("Document is not encrypted\n"); + return ERROR; + } + ret = do_decrypt(m); + if (ret != SUCCESS) { + mobi_free(m); + return ERROR; + } + suffix = "decrypted"; + } + + ret = save_mobi(m, fullpath, suffix); + if (ret != SUCCESS) { + mobi_free(m); + return ERROR; + } + + /* Free MOBIData structure */ + mobi_free(m); + + /* In case of encrypting hybrid file proceed with KF8 part */ + if (encrypt_opt && is_hybrid && use_kf8 == false) { + loadfilename(fullpath); + } + return SUCCESS; +} + +/** + @brief Parse ISO8601 date into tm structure + + @param[in,out] tm Structure to be filled + @param[in] date_str Input date string + @return SUCCESS or ERROR + */ +static int parse_date(struct tm *tm, const char *date_str) { + memset(tm, '\0', sizeof(*tm)); + int year; + int month; + int day; + if (sscanf(date_str, "%5d-%2d-%2d", &year, &month, &day) != 3) { + return ERROR; + } + if (year < 1000 || month < 1 || month > 12 || day < 1 || day > 31) { + return ERROR; + } + + tm->tm_year = year - 1900; + tm->tm_mon = month - 1; + tm->tm_mday = day; + tm->tm_isdst = -1; + + return SUCCESS; +} + +/** + @brief Main + + @param[in] argc Arguments count + @param[in] argv Arguments array + @return SUCCESS (0) or ERROR (1) + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + print_usage(argv[0]); + return ERROR; + } + opterr = 0; + int c; + while ((c = getopt(argc, argv, "def:ho:p:s:t:vx:")) != -1) { + switch(c) { + case 'd': + if (encrypt_opt) { + printf("Options -d and -e can't be used together.\n"); + return ERROR; + } + decrypt_opt = true; + break; + case 'e': + if (decrypt_opt) { + printf("Options -d and -e can't be used together.\n"); + return ERROR; + } + encrypt_opt = true; + break; + case 'f': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + struct tm from; + if (parse_date(&from, optarg) != SUCCESS) { + printf("Wrong valid from date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + valid_from = mktime(&from); + if (valid_from == -1) { + printf("Unparsable valid from date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + expiry_opt = true; + break; + case 'o': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + size_t outdir_length = strlen(optarg); + if (outdir_length >= FILENAME_MAX - 1) { + printf("Output directory name too long\n"); + return ERROR; + } + strncpy(outdir, optarg, FILENAME_MAX - 1); + normalize_path(outdir); + if (!dir_exists(outdir)) { + printf("Output directory is not valid\n"); + return ERROR; + } + if (optarg[outdir_length - 1] != separator) { + // append separator + if (outdir_length >= FILENAME_MAX - 2) { + printf("Output directory name too long\n"); + return ERROR; + } + outdir[outdir_length++] = separator; + outdir[outdir_length] = '\0'; + } + outdir_opt = true; + break; + case 'p': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + if (pid_count < VOUCHERS_COUNT_MAX) { + pid[pid_count++] = optarg; + } else { + printf("Maximum PIDs count reached, skipping PID...\n"); + } + break; + case 's': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + if (serial_count < VOUCHERS_COUNT_MAX) { + serial[serial_count++] = optarg; + } else { + printf("Maximum serial numbers count reached, skipping serial...\n"); + } + break; + case 't': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + struct tm to; + if (parse_date(&to, optarg) != SUCCESS) { + printf("Wrong valid to date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + to.tm_hour = 23; + to.tm_min = 59; + to.tm_sec = 59; + valid_to = mktime(&to); + if (valid_to == -1) { + printf("Unparsable valid to date format, use ISO 8601 yyyy-mm-dd\n"); + return ERROR; + } + expiry_opt = true; + break; + case 'v': + printf("mobidrm build: " __DATE__ " " __TIME__ " (" COMPILER ")\n"); + printf("libmobi: %s\n", mobi_version()); + return SUCCESS; + case '?': + if (isprint(optopt)) { + fprintf(stderr, "Unknown option `-%c'\n", optopt); + } + else { + fprintf(stderr, "Unknown option character `\\x%x'\n", optopt); + } + print_usage(argv[0]); + return ERROR; + case 'h': + default: + print_usage(argv[0]); + return SUCCESS; + } + } + + if (argc <= optind) { + printf("Missing filename\n"); + print_usage(argv[0]); + return ERROR; + } + + if (!decrypt_opt && !encrypt_opt) { + printf("One of -d (decrypt) and -e (encrypt) options is required\n"); + print_usage(argv[0]); + return ERROR; + } + + if (!encrypt_opt && expiry_opt) { + printf("Expiration flags can only be used with -e (encrypt)\n"); + print_usage(argv[0]); + return ERROR; + } + + if (!decrypt_opt && pid_count) { + printf("PID can only be used with -d (decrypt)\n"); + print_usage(argv[0]); + return ERROR; + } + + int ret = 0; + char filename[FILENAME_MAX]; + strncpy(filename, argv[optind], FILENAME_MAX - 1); + filename[FILENAME_MAX - 1] = '\0'; + normalize_path(filename); + + ret = loadfilename(filename); + + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/tools/mobimeta.1.in b/Charcoal/Charcoal/libmobi-public/tools/mobimeta.1.in new file mode 100644 index 0000000..dde1939 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/mobimeta.1.in @@ -0,0 +1,92 @@ +.Dd February 16, 2022 +.Dt mobimeta 1 URM +.Os Unix +.Sh NAME +.Nm mobimeta +.Nd Utility for modifying metadata of MOBI format ebook files. +.Sh SYNOPSIS +.Nm +.Op Fl a Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +.Op Fl d Ar meta Ns Oo , Ns Ar meta Ns , Ns Ar ... Oc +.Op Fl s Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +.if !'@ENCRYPTION_OPT@'yes' .ig +.Op Fl p Ar pid +.Op Fl P Ar serial +.. +.Op Fl hv +.Ar filein +.Op Ar fileout +.Sh DESCRIPTION +The program handles .prc, .mobi, .azw, .azw3, .azw4, some .pdb documents. It is powered by +.Nm libmobi +library. +.Pp +Invoked without arguments prints document metadata and exits. If +.Ar fileout +is specified, modified document will be saved with this name, otherwise original input +.Ar filein +will be modified. +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent +.It Fl a Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +add (append) metadata +.It Fl d Ar meta Ns Oo , Ns Ar meta Ns , Ns Ar ... Oc +delete metadata +.It Fl s Ar meta Ns = Ns Ar value Ns Oo , Ns Ar meta Ns = Ns Ar value Ns , Ns Ar ... Oc +set (replace) metadata +.It Ar meta +for a list of valid named meta keys try +.Nm Bro Fl a | Fl d | Fl s Brc Ar \&? . +If meta is an integer it will be treated as a numeric EXTH record key (expert usage). +.It Ar value +new value that will be set for a given meta key +.if !'@ENCRYPTION_OPT@'yes' .ig +.It Fl p Ar pid +set pid for decryption +.It Fl P Ar serial +set device serial number for decryption +.. +.It Fl h +show usage summary and exit +.It Fl v +show version and exit +.El +.Pp +.Sh EXAMPLES +The following command will set new title, new author and will delete all publisher metadata (if any). +.Pp +.Dl % mobimeta -s title="My title",author="My name" -d publisher example.mobi +.Pp +The following command appends EXTH record identified by its numeric key 204 with numeric value 201. +.Pp +.Dl % mobimeta -a 204=201 example.mobi +.Pp +The following command will list valid meta named keys. +.Pp +.Dl % mobimeta -a \&?\& +.Pp +Or in case your shell expands quotation mark: +.Pp +.Dl % mobimeta -a \&"?"\& +.Sh RETURN VALUES +The +.Nm +utility returns 0 on success, 1 on error. +.Sh COPYRIGHT +Copyright (C) 2014-2022 Bartek Fabiszewski. +.Pp +Released under LGPL version 3 or any later (same as +.Nm libmobi Ns +). +.Sh WEB SITE +Visit http://www.fabiszewski.net for details. +.Sh DIAGNOSTICS +For diagnostics +.Nm libmobi +must be configured with +.Fl Fl enable-debug +option. +.Sh SEE ALSO +.Xr mobitool 1 +.Xr mobidrm 1 diff --git a/Charcoal/Charcoal/libmobi-public/tools/mobimeta.c b/Charcoal/Charcoal/libmobi-public/tools/mobimeta.c new file mode 100644 index 0000000..750bc65 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/mobimeta.c @@ -0,0 +1,398 @@ +/** @file mobimeta.c + * + * @brief mobimeta + * + * @example mobimeta.c + * Program for testing libmobi library + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* encryption */ +#ifdef USE_ENCRYPTION +# define PRINT_ENC_USG " [-p pid] [-P serial]" +# define PRINT_ENC_ARG "p:P:" +#else +# define PRINT_ENC_USG "" +# define PRINT_ENC_ARG "" +#endif + +/* command line options */ +#ifdef USE_ENCRYPTION +bool setpid_opt = false; +bool setserial_opt = false; +#endif + +/* options values */ +#ifdef USE_ENCRYPTION +char *pid = NULL; +char *serial = NULL; +#endif + +#define META_SIZE ARRAYSIZE(meta_functions) +#define ACTIONS_SIZE ARRAYSIZE(actions) + +#if HAVE_ATTRIBUTE_NORETURN +static void exit_with_usage(const char *progname) __attribute__((noreturn)); +#else +static void exit_with_usage(const char *progname); +#endif + +/** + @brief Meta handling functions + */ +typedef MOBI_RET (*MetaFunAdd)(MOBIData *m, const char *string); +typedef MOBI_RET (*MetaFunDel)(MOBIData *m); + +/** + @brief Meta functions structure + */ +typedef struct { + const char *name; + MetaFunAdd function_add; + MetaFunAdd function_set; + MetaFunDel function_del; +} CB; + +const CB meta_functions[] = { + { "author", mobi_meta_add_author, mobi_meta_set_author, mobi_meta_delete_author }, + { "title", mobi_meta_add_title, mobi_meta_set_title, mobi_meta_delete_title }, + { "publisher", mobi_meta_add_publisher, mobi_meta_set_publisher, mobi_meta_delete_publisher }, + { "imprint", mobi_meta_add_imprint, mobi_meta_set_imprint, mobi_meta_delete_imprint }, + { "description", mobi_meta_add_description, mobi_meta_set_description, mobi_meta_delete_description }, + { "isbn", mobi_meta_add_isbn, mobi_meta_set_isbn, mobi_meta_delete_isbn }, + { "subject", mobi_meta_add_subject, mobi_meta_set_subject, mobi_meta_delete_subject }, + { "publishdate", mobi_meta_add_publishdate, mobi_meta_set_publishdate, mobi_meta_delete_publishdate }, + { "review", mobi_meta_add_review, mobi_meta_set_review, mobi_meta_delete_review }, + { "contributor", mobi_meta_add_contributor, mobi_meta_set_contributor, mobi_meta_delete_contributor }, + { "copyright", mobi_meta_add_copyright, mobi_meta_set_copyright, mobi_meta_delete_copyright }, + { "asin", mobi_meta_add_asin, mobi_meta_set_asin, mobi_meta_delete_asin }, + { "language", mobi_meta_add_language, mobi_meta_set_language, mobi_meta_delete_language }, +}; + +/** + @brief Print usage info + @param[in] progname Executed program name + */ +static void exit_with_usage(const char *progname) { + char *p = strrchr(progname, separator); + if (p) { progname = ++p; } + printf("usage: %s [-a | -s meta=value[,meta=value,...]] [-d meta[,meta,...]]" PRINT_ENC_USG " [-hv] filein [fileout]\n", progname); + printf(" without arguments prints document metadata and exits\n"); + printf(" -a ? list valid meta named keys\n"); + printf(" -a meta=value add metadata\n"); + printf(" -d meta delete metadata\n"); + printf(" -s meta=value set metadata\n"); +#ifdef USE_ENCRYPTION + printf(" -p pid set pid for decryption\n"); + printf(" -P serial set device serial for decryption\n"); +#endif + printf(" -h show this usage summary and exit\n"); + printf(" -v show version and exit\n"); + exit(ERROR); +} + +/** + @brief Check whether string is integer + @param[in] string String + @return True if string represents integer + */ +static bool isinteger(const char *string) { + if (*string == '\0') { return false; } + while (*string) { + if (!isdigit(*string++)) { return false; } + } + return true; +} + +/** + @brief Parse suboption's list key=value[,key=value,...] + and get first key-value pair. + @param[in,out] subopts List of suboptions + @param[in,out] token Will be filled with first found key name or NULL if missing + @param[in,out] value Will be filled with first found key value or NULL if missing + @return True if there are more pairs to parse + */ +static bool parsesubopt(char **subopts, char **token, char **value) { + if (!**subopts) { return false; } + *token = NULL; + *value = NULL; + char *p = NULL; + while ((p = (*subopts)++) && *p) { + if (*p == ',') { + *p = '\0'; + return true; + } + if (!*token) { *token = p; } + if (*p == '=') { + *p = '\0'; + *value = ++p; + } + } + return false; +} + +/** + @brief Get matching token from meta functions array + @param[in] token Meta token name + @return Index in array,-1 if not found + */ +static int get_meta(const char *token) { + for (int i = 0; i < (int) META_SIZE; i++) { + if (strcmp(token, meta_functions[i].name) == 0) { + return i; + } + } + return -1; +} + +/** + @brief Main + + @param[in] argc Arguments count + @param[in] argv Arguments array + @return SUCCESS (0) or ERROR (1) + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + exit_with_usage(argv[0]); + } + + typedef struct { + int command; + int meta; + char *value; + } Action; + Action actions[100]; + + size_t cmd_count = 0; + + char *token = NULL; + char *value = NULL; + char *subopts; + int opt; + int subopt; + bool parse; + while ((opt = getopt(argc, argv, "a:d:hs:" PRINT_ENC_ARG "v")) != -1) { + switch (opt) { + case 'a': + case 'd': + case 's': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", opt); + return ERROR; + } + subopts = optarg; + parse = true; + while (parse) { + parse = parsesubopt(&subopts, &token, &value); + if (token && (subopt = get_meta(token)) >= 0) { + if ((value == NULL || strlen(value) == 0) && opt != 'd') { + printf("Missing value for suboption '%s'\n\n", meta_functions[subopt].name); + exit_with_usage(argv[0]); + } + if (cmd_count < (ACTIONS_SIZE)) { + actions[cmd_count++] = (Action) { opt, subopt, value }; + } + } else if (token && isinteger(token)) { + if ((value == NULL || strlen(value) == 0) && opt != 'd') { + printf("Missing value for suboption '%s'\n\n", token); + exit_with_usage(argv[0]); + } + if (cmd_count < (ACTIONS_SIZE)) { + /* mark numeric meta with upper opt */ + actions[cmd_count++] = (Action) { toupper(opt), atoi(token), value }; + } + } else { + if (token == NULL || token[0] != '?') { + printf("Unknown meta: %s\n", token ? token : optarg); + } + printf("Valid named meta keys:\n"); + for (size_t i = 0; i < META_SIZE; i++) { + printf(" %s\n", meta_functions[i].name); + } + printf("\n"); + if (token == NULL || token[0] != '?') { + exit_with_usage(argv[0]); + } + return SUCCESS; + } + } + break; +#ifdef USE_ENCRYPTION + case 'p': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", opt); + return ERROR; + } + setpid_opt = true; + pid = optarg; + break; + case 'P': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", opt); + return ERROR; + } + setserial_opt = true; + serial = optarg; + break; +#endif + case 'v': + printf("mobimeta build: " __DATE__ " " __TIME__ " (" COMPILER ")\n"); + printf("libmobi: %s\n", mobi_version()); + return 0; + case '?': + if (isprint(optopt)) { + printf("Unknown option `-%c'\n", optopt); + } + else { + printf("Unknown option character `\\x%x'\n", optopt); + } + exit_with_usage(argv[0]); + case 'h': + default: + exit_with_usage(argv[0]); + } + } + + int file_args = argc - optind; + if (file_args <= 0) { + printf("Missing filename\n"); + exit_with_usage(argv[0]); + } + char infile[FILENAME_MAX]; + strncpy(infile, argv[optind], FILENAME_MAX - 1); + infile[FILENAME_MAX - 1] = '\0'; + normalize_path(infile); + + if (file_args >= 2) { optind++; } + + char outfile[FILENAME_MAX]; + strncpy(outfile, argv[optind], FILENAME_MAX - 1); + outfile[FILENAME_MAX - 1] = '\0'; + normalize_path(outfile); + + /* Initialize MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Libmobi initialization failed\n"); + return ERROR; + } + + /* read */ + FILE *file_in = fopen(infile, "rb"); + if (file_in == NULL) { + mobi_free(m); + int errsv = errno; + printf("Error opening file: %s (%s)\n", infile, strerror(errsv)); + return ERROR; + } + MOBI_RET mobi_ret = mobi_load_file(m, file_in); + fclose(file_in); + if (mobi_ret != MOBI_SUCCESS) { + mobi_free(m); + printf("Error loading file (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + +#ifdef USE_ENCRYPTION + if (setpid_opt || setserial_opt) { + int ret = set_decryption_key(m, serial, pid); + if (ret != SUCCESS) { + mobi_free(m); + return ret; + } + } +#endif + + if (cmd_count == 0) { + print_summary(m); + print_exth(m); + mobi_free(m); + return SUCCESS; + } + + for (size_t i = 0; i < cmd_count; i++) { + Action action = actions[i]; + MOBIExthMeta tag; + mobi_ret = MOBI_SUCCESS; + switch (action.command) { + /* named meta */ + case 'a': + mobi_ret = meta_functions[action.meta].function_add(m, action.value); + break; + case 'd': + mobi_ret = meta_functions[action.meta].function_del(m); + break; + case 's': + mobi_ret = meta_functions[action.meta].function_set(m, action.value); + break; + /* numeric exth */ + case 'A': + tag = mobi_get_exthtagmeta_by_tag((MOBIExthTag) action.meta); + if (tag.name && tag.type == EXTH_NUMERIC && isinteger(action.value)) { + uint32_t numeric = (uint32_t) atoi(action.value); + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, sizeof(uint32_t), &numeric); + } else { + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, (uint32_t) strlen(action.value), action.value); + } + break; + case 'D': + mobi_ret = mobi_delete_exthrecord_by_tag(m, (MOBIExthTag) action.meta); + break; + case 'S': + mobi_ret = mobi_delete_exthrecord_by_tag(m, (MOBIExthTag) action.meta); + if (mobi_ret != MOBI_SUCCESS) { break; } + tag = mobi_get_exthtagmeta_by_tag((MOBIExthTag) action.meta); + if (tag.name && tag.type == EXTH_NUMERIC && isinteger(action.value)) { + uint32_t numeric = (uint32_t) atoi(action.value); + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, sizeof(uint32_t), &numeric); + } else { + mobi_ret = mobi_add_exthrecord(m, (MOBIExthTag) action.meta, (uint32_t) strlen(action.value), action.value); + } + break; + } + if (mobi_ret != MOBI_SUCCESS) { + printf("Metadata modification failed (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + } + + /* write */ + printf("Saving %s...\n", outfile); + FILE *file_out = fopen(outfile, "wb"); + if (file_out == NULL) { + mobi_free(m); + int errsv = errno; + printf("Error opening file: %s (%s)\n", outfile, strerror(errsv)); + return ERROR; + } + mobi_ret = mobi_write_file(file_out, m); + fclose(file_out); + if (mobi_ret != MOBI_SUCCESS) { + mobi_free(m); + printf("Error writing file (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + + /* Free MOBIData structure */ + mobi_free(m); + + return SUCCESS; +} diff --git a/Charcoal/Charcoal/libmobi-public/tools/mobitool.1.in b/Charcoal/Charcoal/libmobi-public/tools/mobitool.1.in new file mode 100644 index 0000000..0df918e --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/mobitool.1.in @@ -0,0 +1,98 @@ +.Dd February 16, 2022 +.Dt mobitool 1 URM +.Os Unix +.Sh NAME +.Nm mobitool +.Nd Utility for handling MOBI format ebook files. +.Sh SYNOPSIS +.Nm +.if '@XMLWRITER_OPT@'yes' .ig +.Op Fl cdhimrstuvx7 +.. +.if !'@XMLWRITER_OPT@'yes' .ig +.Op Fl cdehimrstuvx7 +.. +.Op Fl o Ar dir +.if !'@ENCRYPTION_OPT@'yes' .ig +.Op Fl p Ar pid +.Op Fl P Ar serial +.. +.Ar file +.Sh DESCRIPTION +The program handles .prc, .mobi, .azw, .azw3, .azw4, some .pdb documents. It is powered by +.Nm libmobi +library. +.Pp +Invoked without arguments prints document metadata and exits. +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent +.It Fl c +dump cover +.It Fl d +dump rawml text record +.if !'@XMLWRITER_OPT@'yes' .ig +.It Fl e +convert mobi to epub +.. +.It Fl h +show usage summary and exit +.It Fl i +print detailed metadata +.It Fl m +print records metadata +.It Fl o Ar dir +save output to dir folder +.if !'@ENCRYPTION_OPT@'yes' .ig +.It Fl p Ar pid +set pid for decryption +.It Fl P Ar serial +set device serial number for decryption +.. +.It Fl r +dump raw records +.It Fl s +dump recreated source files +.It Fl t +split hybrid file into two parts: mobi and azw3 +.It Fl u +show rusage (diagnostics) +.It Fl v +show version and exit +.It Fl x +extract conversion source and log (if present) +.It Fl 7 +parse KF7 part of hybrid file (by default KF8 part is parsed) +.El +.Pp +.Sh EXAMPLES +The following command decompiles given mobi document. The output folder will be created in /tmp. +.Pp +.Dl % mobitool -s -o /tmp example.mobi +.Pp +.if !'@XMLWRITER_OPT@'yes' .ig +The following command converts mobi document to epub format. +.Pp +.Dl % mobitool -e example.mobi +.. +.Sh RETURN VALUES +The +.Nm mobitool +utility returns 0 on success, 1 on error. +.Sh COPYRIGHT +Copyright (C) 2014-2022 Bartek Fabiszewski. +.Pp +Released under LGPL version 3 or any later (same as +.Nm libmobi Ns +). +.Sh WEB SITE +Visit http://www.fabiszewski.net for details. +.Sh DIAGNOSTICS +For diagnostics +.Nm libmobi +must be configured with +.Fl Fl enable-debug +option. +.Sh SEE ALSO +.Xr mobimeta 1 +.Xr mobidrm 1 diff --git a/Charcoal/Charcoal/libmobi-public/tools/mobitool.c b/Charcoal/Charcoal/libmobi-public/tools/mobitool.c new file mode 100644 index 0000000..471b522 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/mobitool.c @@ -0,0 +1,1071 @@ +/** @file mobitool.c + * + * @brief mobitool + * + * @example mobitool.c + * Program for testing libmobi library + * + * Copyright (c) 2020 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#include +#include +#include +#include +#include +#include +/* include libmobi header */ +#include +#include "common.h" + +/* miniz file is needed for EPUB creation */ +#ifdef USE_XMLWRITER +# define MINIZ_HEADER_FILE_ONLY +# define MINIZ_NO_ZLIB_COMPATIBLE_NAMES +# include "../src/miniz.c" +#endif + +#ifdef HAVE_SYS_RESOURCE_H +/* rusage */ +# include +# define PRINT_RUSAGE_ARG "u" +#else +# define PRINT_RUSAGE_ARG "" +#endif +/* encryption */ +#ifdef USE_ENCRYPTION +# define PRINT_ENC_USG " [-p pid] [-P serial]" +# define PRINT_ENC_ARG "p:P:" +#else +# define PRINT_ENC_USG "" +# define PRINT_ENC_ARG "" +#endif +/* xmlwriter */ +#ifdef USE_XMLWRITER +# define PRINT_EPUB_ARG "e" +#else +# define PRINT_EPUB_ARG "" +#endif + +#if HAVE_ATTRIBUTE_NORETURN +static void exit_with_usage(const char *progname) __attribute__((noreturn)); +#else +static void exit_with_usage(const char *progname); +#endif + +#define EPUB_CONTAINER "\n\ +\n\ + \n\ + \n\ + \n\ +" +#define EPUB_MIMETYPE "application/epub+zip" + +/* command line options */ +bool dump_cover_opt = false; +bool dump_rawml_opt = false; +bool create_epub_opt = false; +bool print_extended_meta_opt = false; +bool print_rec_meta_opt = false; +bool dump_rec_opt = false; +bool parse_kf7_opt = false; +bool dump_parts_opt = false; +bool print_rusage_opt = false; +bool extract_source_opt = false; +bool split_opt = false; +#ifdef USE_ENCRYPTION +bool setpid_opt = false; +bool setserial_opt = false; +#endif + +/* options values */ +#ifdef USE_ENCRYPTION +char *pid = NULL; +char *serial = NULL; +#endif + +/** + @brief Print all loaded headers meta information + @param[in] m MOBIData structure + */ +static void print_meta(const MOBIData *m) { + /* Full name stored at offset given in MOBI header */ + if (m->mh && m->mh->full_name) { + char full_name[FULLNAME_MAX + 1]; + if (mobi_get_fullname(m, full_name, FULLNAME_MAX) == MOBI_SUCCESS) { + printf("\nFull name: %s\n", full_name); + } + } + /* Palm database header */ + if (m->ph) { + printf("\nPalm doc header:\n"); + printf("name: %s\n", m->ph->name); + printf("attributes: %hu\n", m->ph->attributes); + printf("version: %hu\n", m->ph->version); + struct tm * timeinfo = mobi_pdbtime_to_time(m->ph->ctime); + printf("ctime: %s", asctime(timeinfo)); + timeinfo = mobi_pdbtime_to_time(m->ph->mtime); + printf("mtime: %s", asctime(timeinfo)); + timeinfo = mobi_pdbtime_to_time(m->ph->btime); + printf("btime: %s", asctime(timeinfo)); + printf("mod_num: %u\n", m->ph->mod_num); + printf("appinfo_offset: %u\n", m->ph->appinfo_offset); + printf("sortinfo_offset: %u\n", m->ph->sortinfo_offset); + printf("type: %s\n", m->ph->type); + printf("creator: %s\n", m->ph->creator); + printf("uid: %u\n", m->ph->uid); + printf("next_rec: %u\n", m->ph->next_rec); + printf("rec_count: %u\n", m->ph->rec_count); + } + /* Record 0 header */ + if (m->rh) { + printf("\nRecord 0 header:\n"); + printf("compression type: %u\n", m->rh->compression_type); + printf("text length: %u\n", m->rh->text_length); + printf("text record count: %u\n", m->rh->text_record_count); + printf("text record size: %u\n", m->rh->text_record_size); + printf("encryption type: %u\n", m->rh->encryption_type); + printf("unknown: %u\n", m->rh->unknown1); + } + /* Mobi header */ + if (m->mh) { + printf("\nMOBI header:\n"); + printf("identifier: %s\n", m->mh->mobi_magic); + if (m->mh->header_length) { printf("header length: %u\n", *m->mh->header_length); } + if (m->mh->mobi_type) { printf("mobi type: %u\n", *m->mh->mobi_type); } + if (m->mh->text_encoding) { printf("text encoding: %u\n", *m->mh->text_encoding); } + if (m->mh->uid) { printf("unique id: %u\n", *m->mh->uid); } + if (m->mh->version) { printf("file version: %u\n", *m->mh->version); } + if (m->mh->orth_index) { printf("orth index: %u\n", *m->mh->orth_index); } + if (m->mh->infl_index) { printf("infl index: %u\n", *m->mh->infl_index); } + if (m->mh->names_index) { printf("names index: %u\n", *m->mh->names_index); } + if (m->mh->keys_index) { printf("keys index: %u\n", *m->mh->keys_index); } + if (m->mh->extra0_index) { printf("extra0 index: %u\n", *m->mh->extra0_index); } + if (m->mh->extra1_index) { printf("extra1 index: %u\n", *m->mh->extra1_index); } + if (m->mh->extra2_index) { printf("extra2 index: %u\n", *m->mh->extra2_index); } + if (m->mh->extra3_index) { printf("extra3 index: %u\n", *m->mh->extra3_index); } + if (m->mh->extra4_index) { printf("extra4 index: %u\n", *m->mh->extra4_index); } + if (m->mh->extra5_index) { printf("extra5 index: %u\n", *m->mh->extra5_index); } + if (m->mh->non_text_index) { printf("non text index: %u\n", *m->mh->non_text_index); } + if (m->mh->full_name_offset) { printf("full name offset: %u\n", *m->mh->full_name_offset); } + if (m->mh->full_name_length) { printf("full name length: %u\n", *m->mh->full_name_length); } + if (m->mh->locale) { + const char *locale_string = mobi_get_locale_string(*m->mh->locale); + if (locale_string) { + printf("locale: %s (%u)\n", locale_string, *m->mh->locale); + } else { + printf("locale: unknown (%u)\n", *m->mh->locale); + } + } + if (m->mh->dict_input_lang) { + const char *locale_string = mobi_get_locale_string(*m->mh->dict_input_lang); + if (locale_string) { + printf("dict input lang: %s (%u)\n", locale_string, *m->mh->dict_input_lang); + } else { + printf("dict input lang: unknown (%u)\n", *m->mh->dict_input_lang); + } + } + if (m->mh->dict_output_lang) { + const char *locale_string = mobi_get_locale_string(*m->mh->dict_output_lang); + if (locale_string) { + printf("dict output lang: %s (%u)\n", locale_string, *m->mh->dict_output_lang); + } else { + printf("dict output lang: unknown (%u)\n", *m->mh->dict_output_lang); + } + } + if (m->mh->min_version) { printf("minimal version: %u\n", *m->mh->min_version); } + if (m->mh->image_index) { printf("first image index: %u\n", *m->mh->image_index); } + if (m->mh->huff_rec_index) { printf("huffman record offset: %u\n", *m->mh->huff_rec_index); } + if (m->mh->huff_rec_count) { printf("huffman records count: %u\n", *m->mh->huff_rec_count); } + if (m->mh->datp_rec_index) { printf("DATP record offset: %u\n", *m->mh->datp_rec_index); } + if (m->mh->datp_rec_count) { printf("DATP records count: %u\n", *m->mh->datp_rec_count); } + if (m->mh->exth_flags) { printf("EXTH flags: %u\n", *m->mh->exth_flags); } + if (m->mh->unknown6) { printf("unknown: %u\n", *m->mh->unknown6); } + if (m->mh->drm_offset) { printf("drm offset: %u\n", *m->mh->drm_offset); } + if (m->mh->drm_count) { printf("drm count: %u\n", *m->mh->drm_count); } + if (m->mh->drm_size) { printf("drm size: %u\n", *m->mh->drm_size); } + if (m->mh->drm_flags) { printf("drm flags: %u\n", *m->mh->drm_flags); } + if (m->mh->first_text_index) { printf("first text index: %u\n", *m->mh->first_text_index); } + if (m->mh->last_text_index) { printf("last text index: %u\n", *m->mh->last_text_index); } + if (m->mh->fdst_index) { printf("FDST offset: %u\n", *m->mh->fdst_index); } + if (m->mh->fdst_section_count) { printf("FDST count: %u\n", *m->mh->fdst_section_count); } + if (m->mh->fcis_index) { printf("FCIS index: %u\n", *m->mh->fcis_index); } + if (m->mh->fcis_count) { printf("FCIS count: %u\n", *m->mh->fcis_count); } + if (m->mh->flis_index) { printf("FLIS index: %u\n", *m->mh->flis_index); } + if (m->mh->flis_count) { printf("FLIS count: %u\n", *m->mh->flis_count); } + if (m->mh->unknown10) { printf("unknown: %u\n", *m->mh->unknown10); } + if (m->mh->unknown11) { printf("unknown: %u\n", *m->mh->unknown11); } + if (m->mh->srcs_index) { printf("SRCS index: %u\n", *m->mh->srcs_index); } + if (m->mh->srcs_count) { printf("SRCS count: %u\n", *m->mh->srcs_count); } + if (m->mh->unknown12) { printf("unknown: %u\n", *m->mh->unknown12); } + if (m->mh->unknown13) { printf("unknown: %u\n", *m->mh->unknown13); } + if (m->mh->extra_flags) { printf("extra record flags: %u\n", *m->mh->extra_flags); } + if (m->mh->ncx_index) { printf("NCX offset: %u\n", *m->mh->ncx_index); } + if (m->mh->unknown14) { printf("unknown: %u\n", *m->mh->unknown14); } + if (m->mh->unknown15) { printf("unknown: %u\n", *m->mh->unknown15); } + if (m->mh->fragment_index) { printf("fragment index: %u\n", *m->mh->fragment_index); } + if (m->mh->skeleton_index) { printf("skeleton index: %u\n", *m->mh->skeleton_index); } + if (m->mh->datp_index) { printf("DATP index: %u\n", *m->mh->datp_index); } + if (m->mh->unknown16) { printf("unknown: %u\n", *m->mh->unknown16); } + if (m->mh->guide_index) { printf("guide index: %u\n", *m->mh->guide_index); } + if (m->mh->unknown17) { printf("unknown: %u\n", *m->mh->unknown17); } + if (m->mh->unknown18) { printf("unknown: %u\n", *m->mh->unknown18); } + if (m->mh->unknown19) { printf("unknown: %u\n", *m->mh->unknown19); } + if (m->mh->unknown20) { printf("unknown: %u\n", *m->mh->unknown20); } + } +} + +/** + @brief Print meta data of each document record + @param[in] m MOBIData structure + */ +static void print_records_meta(const MOBIData *m) { + /* Linked list of MOBIPdbRecord structures holds records data and metadata */ + const MOBIPdbRecord *currec = m->rec; + while (currec != NULL) { + printf("offset: %u\n", currec->offset); + printf("size: %zu\n", currec->size); + printf("attributes: %hhu\n", currec->attributes); + printf("uid: %u\n", currec->uid); + printf("\n"); + currec = currec->next; + } +} + +/** + @brief Create new path. Name is derived from input file path. + [dirname]/[basename][suffix] + @param[out] newpath Created path + @param[in] buf_len Created path buffer size + @param[in] fullpath Input file path + @param[in] suffix Path name suffix + @return SUCCESS or ERROR + */ +static int create_path(char *newpath, const size_t buf_len, const char *fullpath, const char *suffix) { + char dirname[FILENAME_MAX]; + char basename[FILENAME_MAX]; + split_fullpath(fullpath, dirname, basename, FILENAME_MAX); + int n; + if (outdir_opt) { + n = snprintf(newpath, buf_len, "%s%s%s", outdir, basename, suffix); + } else { + n = snprintf(newpath, buf_len, "%s%s%s", dirname, basename, suffix); + } + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= buf_len) { + printf("File name too long\n"); + return ERROR; + } + return SUCCESS; +} + +/** + @brief Create directory. Path is derived from input file path. + [dirname]/[basename][suffix] + @param[out] newdir Created directory path + @param[in] buf_len Created directory buffer size + @param[in] fullpath Input file path + @param[in] suffix Directory name suffix + @return SUCCESS or ERROR + */ +static int create_dir(char *newdir, const size_t buf_len, const char *fullpath, const char *suffix) { + if (create_path(newdir, buf_len, fullpath, suffix) == ERROR) { + return ERROR; + } + return make_directory(newdir); +} + +/** + @brief Dump each document record to a file into created folder + @param[in] m MOBIData structure + @param[in] fullpath File path will be parsed to build basenames of dumped records + @return SUCCESS or ERROR + */ +static int dump_records(const MOBIData *m, const char *fullpath) { + char newdir[FILENAME_MAX]; + if (create_dir(newdir, sizeof(newdir), fullpath, "_records") == ERROR) { + return ERROR; + } + printf("Saving records to %s\n", newdir); + /* Linked list of MOBIPdbRecord structures holds records data and metadata */ + const MOBIPdbRecord *currec = m->rec; + int i = 0; + while (currec != NULL) { + char name[FILENAME_MAX]; + snprintf(name, sizeof(name), "record_%i_uid_%i", i++, currec->uid); + if (write_to_dir(newdir, name, currec->data, currec->size) == ERROR) { + return ERROR; + } + + currec = currec->next; + } + return SUCCESS; +} + +/** + @brief Dump all text records, decompressed and concatenated, to a single rawml file + @param[in] m MOBIData structure + @param[in] fullpath File path will be parsed to create a new name for saved file + @return SUCCESS or ERROR + */ +static int dump_rawml(const MOBIData *m, const char *fullpath) { + char newpath[FILENAME_MAX]; + if (create_path(newpath, sizeof(newpath), fullpath, ".rawml") == ERROR) { + return ERROR; + } + printf("Saving rawml to %s\n", newpath); + errno = 0; + FILE *file = fopen(newpath, "wb"); + if (file == NULL) { + int errsv = errno; + printf("Could not open file for writing: %s (%s)\n", newpath, strerror(errsv)); + return ERROR; + } + const MOBI_RET mobi_ret = mobi_dump_rawml(m, file); + fclose(file); + if (mobi_ret != MOBI_SUCCESS) { + printf("Dumping rawml file failed (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + return SUCCESS; +} + +/** + @brief Dump cover record + @param[in] m MOBIData structure + @param[in] fullpath File path will be parsed to create a new name for saved file + @return SUCCESS or ERROR + */ +static int dump_cover(const MOBIData *m, const char *fullpath) { + + MOBIPdbRecord *record = NULL; + MOBIExthHeader *exth = mobi_get_exthrecord_by_tag(m, EXTH_COVEROFFSET); + if (exth) { + uint32_t offset = mobi_decode_exthvalue(exth->data, exth->size); + size_t first_resource = mobi_get_first_resource_record(m); + size_t uid = first_resource + offset; + record = mobi_get_record_by_seqnumber(m, uid); + } + if (record == NULL || record->size < 4) { + printf("Cover not found\n"); + return ERROR; + } + + const unsigned char jpg_magic[] = "\xff\xd8\xff"; + const unsigned char gif_magic[] = "\x47\x49\x46\x38"; + const unsigned char png_magic[] = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; + const unsigned char bmp_magic[] = "\x42\x4d"; + + char ext[4] = "raw"; + if (memcmp(record->data, jpg_magic, 3) == 0) { + snprintf(ext, sizeof(ext), "%s", "jpg"); + } else if (memcmp(record->data, gif_magic, 4) == 0) { + snprintf(ext, sizeof(ext), "%s", "gif"); + } else if (record->size >= 8 && memcmp(record->data, png_magic, 8) == 0) { + snprintf(ext, sizeof(ext), "%s", "png"); + } else if (record->size >= 6 && memcmp(record->data, bmp_magic, 2) == 0) { + const size_t bmp_size = (uint32_t) record->data[2] | ((uint32_t) record->data[3] << 8) | + ((uint32_t) record->data[4] << 16) | ((uint32_t) record->data[5] << 24); + if (record->size == bmp_size) { + snprintf(ext, sizeof(ext), "%s", "bmp"); + } + } + + char suffix[12]; + snprintf(suffix, sizeof(suffix), "_cover.%s", ext); + + char cover_path[FILENAME_MAX]; + if (create_path(cover_path, sizeof(cover_path), fullpath, suffix) == ERROR) { + return ERROR; + } + + printf("Saving cover to %s\n", cover_path); + + return write_file(record->data, record->size, cover_path); +} + +/** + @brief Dump parsed markup files and resources into created folder + @param[in] rawml MOBIRawml structure holding parsed records + @param[in] fullpath File path will be parsed to build basenames of dumped records + @return SUCCESS or ERROR + */ +static int dump_rawml_parts(const MOBIRawml *rawml, const char *fullpath) { + if (rawml == NULL) { + printf("Rawml structure not initialized\n"); + return ERROR; + } + + char newdir[FILENAME_MAX]; + if (create_dir(newdir, sizeof(newdir), fullpath, "_markup") == ERROR) { + return ERROR; + } + printf("Saving markup to %s\n", newdir); + + if (create_epub_opt) { + /* create META_INF directory */ + char opfdir[FILENAME_MAX]; + if (create_subdir(opfdir, sizeof(opfdir), newdir, "META-INF") == ERROR) { + return ERROR; + } + + /* create container.xml */ + if (write_to_dir(opfdir, "container.xml", (const unsigned char *) EPUB_CONTAINER, sizeof(EPUB_CONTAINER) - 1) == ERROR) { + return ERROR; + } + + /* create mimetype file */ + if (write_to_dir(opfdir, "mimetype", (const unsigned char *) EPUB_MIMETYPE, sizeof(EPUB_MIMETYPE) - 1) == ERROR) { + return ERROR; + } + + /* create OEBPS directory */ + if (create_subdir(opfdir, sizeof(opfdir), newdir, "OEBPS") == ERROR) { + return ERROR; + } + + /* output everything else to OEBPS dir */ + strcpy(newdir, opfdir); + } + char partname[FILENAME_MAX]; + if (rawml->markup != NULL) { + /* Linked list of MOBIPart structures in rawml->markup holds main text files */ + MOBIPart *curr = rawml->markup; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "part%05zu.%s", curr->uid, file_meta.extension); + if (write_to_dir(newdir, partname, curr->data, curr->size) == ERROR) { + return ERROR; + } + printf("%s\n", partname); + curr = curr->next; + } + } + if (rawml->flow != NULL) { + /* Linked list of MOBIPart structures in rawml->flow holds supplementary text files */ + MOBIPart *curr = rawml->flow; + /* skip raw html file */ + curr = curr->next; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "flow%05zu.%s", curr->uid, file_meta.extension); + if (write_to_dir(newdir, partname, curr->data, curr->size) == ERROR) { + return ERROR; + } + printf("%s\n", partname); + curr = curr->next; + } + } + if (rawml->resources != NULL) { + /* Linked list of MOBIPart structures in rawml->resources holds binary files, also opf files */ + MOBIPart *curr = rawml->resources; + /* jpg, gif, png, bmp, font, audio, video also opf, ncx */ + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + if (curr->size > 0) { + int n; + if (create_epub_opt && file_meta.type == T_OPF) { + n = snprintf(partname, sizeof(partname), "%s%ccontent.opf", newdir, separator); + } else { + n = snprintf(partname, sizeof(partname), "%s%cresource%05zu.%s", newdir, separator, curr->uid, file_meta.extension); + } + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(partname)) { + printf("File name too long: %s\n", partname); + return ERROR; + } + + if (create_epub_opt && file_meta.type == T_OPF) { + printf("content.opf\n"); + } else { + printf("resource%05zu.%s\n", curr->uid, file_meta.extension); + } + + if (write_file(curr->data, curr->size, partname) == ERROR) { + return ERROR; + } + + } + curr = curr->next; + } + } + return SUCCESS; +} + +#ifdef USE_XMLWRITER +/** + @brief Bundle recreated source files into EPUB container + + This function is a simple example. + In real world implementation one should validate and correct all input + markup to check if it conforms to OPF and HTML specifications and + correct all the issues. + + @param[in] rawml MOBIRawml structure holding parsed records + @param[in] fullpath File path will be parsed to build basenames of dumped records + @return SUCCESS or ERROR + */ +static int create_epub(const MOBIRawml *rawml, const char *fullpath) { + if (rawml == NULL) { + printf("Rawml structure not initialized\n"); + return ERROR; + } + + char zipfile[FILENAME_MAX]; + if (create_path(zipfile, sizeof(zipfile), fullpath, ".epub") == ERROR) { + return ERROR; + } + printf("Saving EPUB to %s\n", zipfile); + + /* create zip (epub) archive */ + mz_zip_archive zip; + memset(&zip, 0, sizeof(mz_zip_archive)); + mz_bool mz_ret = mz_zip_writer_init_file(&zip, zipfile, 0); + if (!mz_ret) { + printf("Could not initialize zip archive\n"); + return ERROR; + } + /* start adding files to archive */ + mz_ret = mz_zip_writer_add_mem(&zip, "mimetype", EPUB_MIMETYPE, sizeof(EPUB_MIMETYPE) - 1, MZ_NO_COMPRESSION); + if (!mz_ret) { + printf("Could not add mimetype\n"); + mz_zip_writer_end(&zip); + return ERROR; + } + mz_ret = mz_zip_writer_add_mem(&zip, "META-INF/container.xml", EPUB_CONTAINER, sizeof(EPUB_CONTAINER) - 1, (mz_uint)MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add container.xml\n"); + mz_zip_writer_end(&zip); + return ERROR; + } + char partname[FILENAME_MAX]; + if (rawml->markup != NULL) { + /* Linked list of MOBIPart structures in rawml->markup holds main text files */ + MOBIPart *curr = rawml->markup; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "OEBPS/part%05zu.%s", curr->uid, file_meta.extension); + mz_ret = mz_zip_writer_add_mem(&zip, partname, curr->data, curr->size, (mz_uint) MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add file to archive: %s\n", partname); + mz_zip_writer_end(&zip); + return ERROR; + } + curr = curr->next; + } + } + if (rawml->flow != NULL) { + /* Linked list of MOBIPart structures in rawml->flow holds supplementary text files */ + MOBIPart *curr = rawml->flow; + /* skip raw html file */ + curr = curr->next; + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + snprintf(partname, sizeof(partname), "OEBPS/flow%05zu.%s", curr->uid, file_meta.extension); + mz_ret = mz_zip_writer_add_mem(&zip, partname, curr->data, curr->size, (mz_uint) MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add file to archive: %s\n", partname); + mz_zip_writer_end(&zip); + return ERROR; + } + curr = curr->next; + } + } + if (rawml->resources != NULL) { + /* Linked list of MOBIPart structures in rawml->resources holds binary files, also opf files */ + MOBIPart *curr = rawml->resources; + /* jpg, gif, png, bmp, font, audio, video, also opf, ncx */ + while (curr != NULL) { + MOBIFileMeta file_meta = mobi_get_filemeta_by_type(curr->type); + if (curr->size > 0) { + if (file_meta.type == T_OPF) { + snprintf(partname, sizeof(partname), "OEBPS/content.opf"); + } else { + snprintf(partname, sizeof(partname), "OEBPS/resource%05zu.%s", curr->uid, file_meta.extension); + } + mz_ret = mz_zip_writer_add_mem(&zip, partname, curr->data, curr->size, (mz_uint) MZ_DEFAULT_COMPRESSION); + if (!mz_ret) { + printf("Could not add file to archive: %s\n", partname); + mz_zip_writer_end(&zip); + return ERROR; + } + } + curr = curr->next; + } + } + /* Finalize epub archive */ + mz_ret = mz_zip_writer_finalize_archive(&zip); + if (!mz_ret) { + printf("Could not finalize zip archive\n"); + mz_zip_writer_end(&zip); + return ERROR; + } + mz_ret = mz_zip_writer_end(&zip); + if (!mz_ret) { + printf("Could not finalize zip writer\n"); + return ERROR; + } + return SUCCESS; +} +#endif + +/** + @brief Dump SRCS record + @param[in] m MOBIData structure + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int dump_embedded_source(const MOBIData *m, const char *fullpath) { + /* Try to get embedded source */ + unsigned char *data = NULL; + size_t size = 0; + MOBI_RET mobi_ret = mobi_get_embedded_source(&data, &size, m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Extracting source from mobi failed (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + if (data == NULL || size == 0 ) { + printf("Source archive not found\n"); + return SUCCESS; + } + + char newdir[FILENAME_MAX]; + if (create_dir(newdir, sizeof(newdir), fullpath, "_source") == ERROR) { + return ERROR; + } + + const unsigned char epub_magic[] = "mimetypeapplication/epub+zip"; + const size_t em_offset = 30; + const size_t em_size = sizeof(epub_magic) - 1; + const char *ext; + if (size > em_offset + em_size && memcmp(data + em_offset, epub_magic, em_size) == 0) { + ext = "epub"; + } else { + ext = "zip"; + } + + char srcsname[FILENAME_MAX]; + char basename[FILENAME_MAX]; + split_fullpath(fullpath, NULL, basename, FILENAME_MAX); + int n = snprintf(srcsname, sizeof(srcsname), "%s_source.%s", basename, ext); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(srcsname)) { + printf("File name too long\n"); + return ERROR; + } + if (write_to_dir(newdir, srcsname, data, size) == ERROR) { + return ERROR; + } + printf("Saving source archive to %s\n", srcsname); + + /* Try to get embedded conversion log */ + data = NULL; + size = 0; + mobi_ret = mobi_get_embedded_log(&data, &size, m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Extracting conversion log from mobi failed (%s)\n", libmobi_msg(mobi_ret)); + return ERROR; + } + if (data == NULL || size == 0 ) { + printf("Conversion log not found\n"); + return SUCCESS; + } + + n = snprintf(srcsname, sizeof(srcsname), "%s_source.txt", basename); + if (n < 0) { + printf("Creating file name failed\n"); + return ERROR; + } + if ((size_t) n >= sizeof(srcsname)) { + printf("File name too long\n"); + return ERROR; + } + if (write_to_dir(newdir, srcsname, data, size) == ERROR) { + return ERROR; + } + printf("Saving conversion log to %s\n", srcsname); + + return SUCCESS; +} + +/** + @brief Split hybrid file in two parts + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int split_hybrid(const char *fullpath) { + + static int run_count = 0; + run_count++; + + bool use_kf8 = run_count == 1 ? false : true; + + /* Initialize main MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Memory allocation failed\n"); + return ERROR; + } + + errno = 0; + FILE *file = fopen(fullpath, "rb"); + if (file == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", fullpath, strerror(errsv)); + mobi_free(m); + return ERROR; + } + /* MOBIData structure will be filled with loaded document data and metadata */ + MOBI_RET mobi_ret = mobi_load_file(m, file); + fclose(file); + + if (mobi_ret != MOBI_SUCCESS) { + printf("Error while loading document (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + mobi_ret = mobi_remove_hybrid_part(m, use_kf8); + if (mobi_ret != MOBI_SUCCESS) { + printf("Error removing hybrid part (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + if (save_mobi(m, fullpath, "split") != SUCCESS) { + printf("Error saving file\n"); + mobi_free(m); + return ERROR; + } + + /* Free MOBIData structure */ + mobi_free(m); + + /* Proceed with KF8 part */ + if (use_kf8 == false) { + split_hybrid(fullpath); + } + + return SUCCESS; +} + +/** + @brief Main routine that calls optional subroutines + @param[in] fullpath Full file path + @return SUCCESS or ERROR + */ +static int loadfilename(const char *fullpath) { + MOBI_RET mobi_ret; + int ret = SUCCESS; + /* Initialize main MOBIData structure */ + MOBIData *m = mobi_init(); + if (m == NULL) { + printf("Memory allocation failed\n"); + return ERROR; + } + /* By default loader will parse KF8 part of hybrid KF7/KF8 file */ + if (parse_kf7_opt) { + /* Force it to parse KF7 part */ + mobi_parse_kf7(m); + } + errno = 0; + FILE *file = fopen(fullpath, "rb"); + if (file == NULL) { + int errsv = errno; + printf("Error opening file: %s (%s)\n", fullpath, strerror(errsv)); + mobi_free(m); + return ERROR; + } + /* MOBIData structure will be filled with loaded document data and metadata */ + mobi_ret = mobi_load_file(m, file); + fclose(file); + + /* Try to print basic metadata, even if further loading failed */ + /* In case of some unsupported formats it may still print some useful info */ + if (print_extended_meta_opt) { print_meta(m); } + + if (mobi_ret != MOBI_SUCCESS) { + printf("Error while loading document (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + return ERROR; + } + + if (create_epub_opt && mobi_is_replica(m)) { + create_epub_opt = false; + printf("\nWarning: Can't create EPUB format from Print Replica book (ignoring -e argument)\n\n"); + } + + if (!print_extended_meta_opt) { + print_summary(m); + } + + if (print_extended_meta_opt) { + /* Try to print EXTH metadata */ + print_exth(m); + } + +#ifdef USE_ENCRYPTION + if (setpid_opt || setserial_opt) { + ret = set_decryption_key(m, serial, pid); + if (ret != SUCCESS) { + mobi_free(m); + return ret; + } + } +#endif + if (print_rec_meta_opt) { + printf("\nPrinting records metadata...\n"); + print_records_meta(m); + } + if (dump_rec_opt) { + printf("\nDumping raw records...\n"); + ret = dump_records(m, fullpath); + } + if (dump_rawml_opt) { + printf("\nDumping rawml...\n"); + ret = dump_rawml(m, fullpath); + } else if (dump_parts_opt || create_epub_opt) { + printf("\nReconstructing source resources...\n"); + /* Initialize MOBIRawml structure */ + /* This structure will be filled with parsed records data */ + MOBIRawml *rawml = mobi_init_rawml(m); + if (rawml == NULL) { + printf("Memory allocation failed\n"); + mobi_free(m); + return ERROR; + } + + /* Parse rawml text and other data held in MOBIData structure into MOBIRawml structure */ + mobi_ret = mobi_parse_rawml(rawml, m); + if (mobi_ret != MOBI_SUCCESS) { + printf("Parsing rawml failed (%s)\n", libmobi_msg(mobi_ret)); + mobi_free(m); + mobi_free_rawml(rawml); + return ERROR; + } + if (create_epub_opt && !dump_parts_opt) { +#ifdef USE_XMLWRITER + printf("\nCreating EPUB...\n"); + /* Create epub file */ + ret = create_epub(rawml, fullpath); + if (ret != SUCCESS) { + printf("Creating EPUB failed\n"); + } +#endif + } else { + printf("\nDumping resources...\n"); + /* Save parts to files */ + ret = dump_rawml_parts(rawml, fullpath); + if (ret != SUCCESS) { + printf("Dumping parts failed\n"); + } + } + /* Free MOBIRawml structure */ + mobi_free_rawml(rawml); + } + if (extract_source_opt) { + ret = dump_embedded_source(m, fullpath); + } + if (dump_cover_opt) { + ret = dump_cover(m, fullpath); + } + if (split_opt && !mobi_is_hybrid(m)) { + printf("File is not a hybrid, skip splitting\n"); + split_opt = false; + } + /* Free MOBIData structure */ + mobi_free(m); + return ret; +} + +/** + @brief Print usage info + @param[in] progname Executed program name + */ +static void exit_with_usage(const char *progname) { + printf("usage: %s [-cd" PRINT_EPUB_ARG "himrst" PRINT_RUSAGE_ARG "vx7] [-o dir]" PRINT_ENC_USG " filename\n", progname); + printf(" without arguments prints document metadata and exits\n"); + printf(" -c dump cover\n"); + printf(" -d dump rawml text record\n"); +#ifdef USE_XMLWRITER + printf(" -e create EPUB file (with -s will dump EPUB source)\n"); +#endif + printf(" -h show this usage summary and exit\n"); + printf(" -i print detailed metadata\n"); + printf(" -m print records metadata\n"); + printf(" -o dir save output to dir folder\n"); +#ifdef USE_ENCRYPTION + printf(" -p pid set pid for decryption\n"); + printf(" -P serial set device serial for decryption\n"); +#endif + printf(" -r dump raw records\n"); + printf(" -s dump recreated source files\n"); + printf(" -t split hybrid file into two parts\n"); +#ifdef HAVE_SYS_RESOURCE_H + printf(" -u show rusage\n"); +#endif + printf(" -v show version and exit\n"); + printf(" -x extract conversion source and log (if present)\n"); + printf(" -7 parse KF7 part of hybrid file (by default KF8 part is parsed)\n"); + exit(SUCCESS); +} + +/** + @brief Main + + @param[in] argc Arguments count + @param[in] argv Arguments array + @return SUCCESS (0) or ERROR (1) + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + exit_with_usage(argv[0]); + } + opterr = 0; + int c; + while ((c = getopt(argc, argv, "cd" PRINT_EPUB_ARG "himo:" PRINT_ENC_ARG "rst" PRINT_RUSAGE_ARG "vx7")) != -1) { + switch (c) { + case 'c': + dump_cover_opt = true; + break; + case 'd': + dump_rawml_opt = true; + break; +#ifdef USE_XMLWRITER + case 'e': + create_epub_opt = true; + break; +#endif + case 'i': + print_extended_meta_opt = true; + break; + case 'm': + print_rec_meta_opt = true; + break; + case 'o': + outdir_opt = true; + size_t outdir_length = strlen(optarg); + if (outdir_length == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + if (outdir_length >= FILENAME_MAX - 1) { + printf("Output directory name too long\n"); + return ERROR; + } + strncpy(outdir, optarg, FILENAME_MAX - 1); + normalize_path(outdir); + if (!dir_exists(outdir)) { + printf("Output directory is not valid\n"); + return ERROR; + } + if (optarg[outdir_length - 1] != separator) { + // append separator + if (outdir_length >= FILENAME_MAX - 2) { + printf("Output directory name too long\n"); + return ERROR; + } + outdir[outdir_length++] = separator; + outdir[outdir_length] = '\0'; + } + break; +#ifdef USE_ENCRYPTION + case 'p': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + setpid_opt = true; + pid = optarg; + break; + case 'P': + if (strlen(optarg) == 2 && optarg[0] == '-') { + printf("Option -%c requires an argument.\n", c); + return ERROR; + } + setserial_opt = true; + serial = optarg; + break; +#endif + case 'r': + dump_rec_opt = true; + break; + case 's': + dump_parts_opt = true; + break; + case 't': + split_opt = true; + break; +#ifdef HAVE_SYS_RESOURCE_H + case 'u': + print_rusage_opt = true; + break; +#endif + case 'v': + printf("mobitool build: " __DATE__ " " __TIME__ " (" COMPILER ")\n"); + printf("libmobi: %s\n", mobi_version()); + return SUCCESS; + case 'x': + extract_source_opt = true; + break; + case '7': + parse_kf7_opt = true; + break; + case '?': + if (isprint(optopt)) { + fprintf(stderr, "Unknown option `-%c'\n", optopt); + } + else { + fprintf(stderr, "Unknown option character `\\x%x'\n", optopt); + } + exit_with_usage(argv[0]); + case 'h': + default: + exit_with_usage(argv[0]); + } + } + if (argc <= optind) { + printf("Missing filename\n"); + exit_with_usage(argv[0]); + } + + int ret = SUCCESS; + char filename[FILENAME_MAX]; + strncpy(filename, argv[optind], FILENAME_MAX - 1); + filename[FILENAME_MAX - 1] = '\0'; + normalize_path(filename); + + ret = loadfilename(filename); + if (split_opt) { + printf("\nSplitting hybrid file...\n"); + ret = split_hybrid(filename); + } +#ifdef HAVE_SYS_RESOURCE_H + if (print_rusage_opt) { + /* rusage */ + struct rusage ru; + struct timeval utime; + struct timeval stime; + getrusage(RUSAGE_SELF, &ru); + utime = ru.ru_utime; + stime = ru.ru_stime; + printf("RUSAGE: ru_utime => %lld.%lld sec.; ru_stime => %lld.%lld sec.\n", + (long long) utime.tv_sec, (long long) utime.tv_usec, + (long long) stime.tv_sec, (long long) stime.tv_usec); + } +#endif + return ret; +} diff --git a/Charcoal/Charcoal/libmobi-public/tools/win32/getopt.c b/Charcoal/Charcoal/libmobi-public/tools/win32/getopt.c new file mode 100644 index 0000000..01bd693 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/win32/getopt.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "getopt.h" + +int opterr = 1, /* if error message should be printed */ +optind = 1, /* index into parent argv vector */ +optopt, /* character checked for validity */ +optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + const char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)printf("illegal option -- %c\n", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)printf("option requires an argument -- %c\n", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/Charcoal/Charcoal/libmobi-public/tools/win32/getopt.h b/Charcoal/Charcoal/libmobi-public/tools/win32/getopt.h new file mode 100644 index 0000000..3b15d46 --- /dev/null +++ b/Charcoal/Charcoal/libmobi-public/tools/win32/getopt.h @@ -0,0 +1,20 @@ +/** @file getopt.h +* +* Copyright (c) 2016 Bartek Fabiszewski +* http://www.fabiszewski.net +* +* Licensed under LGPL, either version 3, or any later. +* See +*/ + +/** Supply getopt header for Win32 builds */ + +#ifndef libmobi_getopt_h +#define libmobi_getopt_h + +extern int opterr, optind, optopt, optreset; +extern char *optarg; + +int getopt(int nargc, char *const nargv[], const char *ostr); + +#endif diff --git a/Charcoal/Charcoal/mobi.h b/Charcoal/Charcoal/mobi.h new file mode 100644 index 0000000..4afbd15 --- /dev/null +++ b/Charcoal/Charcoal/mobi.h @@ -0,0 +1,623 @@ +/** @file mobi.h + * @brief Libmobi main header file + * + * This file is installed with the library. + * Include it in your project with "#include ". + * See example of usage in mobitool.c, mobimeta.c, mobidrm.c + * + * Copyright (c) 2014-2022 Bartek Fabiszewski + * http://www.fabiszewski.net + * + * This file is part of libmobi. + * Licensed under LGPL, either version 3, or any later. + * See + */ + +#ifndef libmobi_mobi_h +#define libmobi_mobi_h + +#include +#include +#include +#include + +/** @brief Visibility attributes for symbol export */ +#if defined (__CYGWIN__) || defined (__MINGW32__) +#define MOBI_EXPORT __attribute__((visibility("default"))) __declspec(dllexport) extern +#elif defined (_WIN32) +#define MOBI_EXPORT __declspec(dllexport) +#else +#define MOBI_EXPORT __attribute__((__visibility__("default"))) +#endif + +/** + @brief Usually 32-bit values in mobi records + with value 0xffffffff mean "value not set" + */ +#define MOBI_NOTSET UINT32_MAX + +#define MOBI_ENCRYPTION_NONE 0 /**< Text record encryption type: none */ +#define MOBI_ENCRYPTION_V1 1 /**< Text record encryption type: old mobipocket */ +#define MOBI_ENCRYPTION_V2 2 /**< Text record encryption type: mobipocket */ + +#define MOBI_COMPRESSION_NONE 1 /**< Text record compression type: none */ +#define MOBI_COMPRESSION_PALMDOC 2 /**< Text record compression type: palmdoc */ +#define MOBI_COMPRESSION_HUFFCDIC 17480 /**< Text record compression type: huff/cdic */ + +#ifdef __cplusplus +extern "C" +{ +#endif + /** + @defgroup mobi_enums Exported enums + @{ + */ + + /** + @brief Error codes returned by functions + */ + typedef enum { + MOBI_SUCCESS = 0, /**< Generic success return value */ + MOBI_ERROR = 1, /**< Generic error return value */ + MOBI_PARAM_ERR = 2, /**< Wrong function parameter */ + MOBI_DATA_CORRUPT = 3, /**< Corrupted data */ + MOBI_FILE_NOT_FOUND = 4, /**< File not found */ + MOBI_FILE_ENCRYPTED = 5, /**< Unsupported encrypted data */ + MOBI_FILE_UNSUPPORTED = 6, /**< Unsupported document type */ + MOBI_MALLOC_FAILED = 7, /**< Memory allocation error */ + MOBI_INIT_FAILED = 8, /**< Initialization error */ + MOBI_BUFFER_END = 9, /**< Out of buffer error */ + MOBI_XML_ERR = 10, /**< XMLwriter error */ + MOBI_DRM_PIDINV = 11, /**< Invalid DRM PID */ + MOBI_DRM_KEYNOTFOUND = 12, /**< Key not found */ + MOBI_DRM_UNSUPPORTED = 13, /**< DRM support not included */ + MOBI_WRITE_FAILED = 14, /**< Writing to file failed */ + MOBI_DRM_EXPIRED = 15, /**< DRM expired */ + MOBI_DRM_RANDOM_ERR = 16 /**< DRM random bytes generation failed */ + } MOBI_RET; + + /** + @brief EXTH record types + */ + typedef enum { + EXTH_NUMERIC = 0, + EXTH_STRING = 1, + EXTH_BINARY = 2 + } MOBIExthType; + + /** + @brief EXTH record tags + */ + typedef enum { + EXTH_DRMSERVER = 1, + EXTH_DRMCOMMERCE = 2, + EXTH_DRMEBOOKBASE = 3, + + EXTH_TITLE = 99, /**< */ + EXTH_AUTHOR = 100, /**< */ + EXTH_PUBLISHER = 101, /**< */ + EXTH_IMPRINT = 102, /**< */ + EXTH_DESCRIPTION = 103, /**< */ + EXTH_ISBN = 104, /**< */ + EXTH_SUBJECT = 105, /**< */ + EXTH_PUBLISHINGDATE = 106, /**< */ + EXTH_REVIEW = 107, /**< */ + EXTH_CONTRIBUTOR = 108, /**< */ + EXTH_RIGHTS = 109, /**< */ + EXTH_SUBJECTCODE = 110, /**< */ + EXTH_TYPE = 111, /**< */ + EXTH_SOURCE = 112, /**< */ + EXTH_ASIN = 113, + EXTH_VERSION = 114, + EXTH_SAMPLE = 115, + EXTH_STARTREADING = 116, /**< Start reading */ + EXTH_ADULT = 117, /**< */ + EXTH_PRICE = 118, /**< */ + EXTH_CURRENCY = 119, /**< */ + EXTH_KF8BOUNDARY = 121, + EXTH_FIXEDLAYOUT = 122, /**< */ + EXTH_BOOKTYPE = 123, /**< */ + EXTH_ORIENTATIONLOCK = 124, /**< */ + EXTH_COUNTRESOURCES = 125, + EXTH_ORIGRESOLUTION = 126, /**< */ + EXTH_ZEROGUTTER = 127, /**< */ + EXTH_ZEROMARGIN = 128, /**< */ + EXTH_KF8COVERURI = 129, + EXTH_RESCOFFSET = 131, + EXTH_REGIONMAGNI = 132, /**< */ + + EXTH_DICTNAME = 200, /**< */ + EXTH_COVEROFFSET = 201, /**< */ + EXTH_THUMBOFFSET = 202, + EXTH_HASFAKECOVER = 203, + EXTH_CREATORSOFT = 204, + EXTH_CREATORMAJOR = 205, + EXTH_CREATORMINOR = 206, + EXTH_CREATORBUILD = 207, + EXTH_WATERMARK = 208, + EXTH_TAMPERKEYS = 209, + + EXTH_FONTSIGNATURE = 300, + + EXTH_CLIPPINGLIMIT = 401, + EXTH_PUBLISHERLIMIT = 402, + EXTH_UNK403 = 403, + EXTH_TTSDISABLE = 404, + EXTH_READFORFREE = 405, // uint32_t, rental related, ReadForFree + EXTH_RENTAL = 406, // uint64_t + EXTH_UNK407 = 407, + EXTH_UNK450 = 450, + EXTH_UNK451 = 451, + EXTH_UNK452 = 452, + EXTH_UNK453 = 453, + + EXTH_DOCTYPE = 501, /**< PDOC - Personal Doc; EBOK - ebook; EBSP - ebook sample; */ + EXTH_LASTUPDATE = 502, + EXTH_UPDATEDTITLE = 503, + EXTH_ASIN504 = 504, + EXTH_TITLEFILEAS = 508, + EXTH_CREATORFILEAS = 517, + EXTH_PUBLISHERFILEAS = 522, + EXTH_LANGUAGE = 524, /**< */ + EXTH_ALIGNMENT = 525, /**< */ + EXTH_CREATORSTRING = 526, + EXTH_PAGEDIR = 527, + EXTH_OVERRIDEFONTS = 528, /**< */ + EXTH_SORCEDESC = 529, + EXTH_DICTLANGIN = 531, + EXTH_DICTLANGOUT = 532, + EXTH_INPUTSOURCE = 534, + EXTH_CREATORBUILDREV = 535, + } MOBIExthTag; + + /** + @brief Types of files stored in database records + */ + typedef enum { + T_UNKNOWN, /**< unknown */ + /* markup */ + T_HTML, /**< html */ + T_CSS, /**< css */ + T_SVG, /**< svg */ + T_OPF, /**< opf */ + T_NCX, /**< ncx */ + /* images */ + T_JPG, /**< jpg */ + T_GIF, /**< gif */ + T_PNG, /**< png */ + T_BMP, /**< bmp */ + /* fonts */ + T_OTF, /**< otf */ + T_TTF, /**< ttf */ + /* media */ + T_MP3, /**< mp3 */ + T_MPG, /**< mp3 */ + T_PDF, /**< pdf */ + /* generic types */ + T_FONT, /**< encoded font */ + T_AUDIO, /**< audio resource */ + T_VIDEO, /**< video resource */ + T_BREAK /**< end of file */ + } MOBIFiletype; + + /** + @brief Metadata of file types + */ + typedef struct { + MOBIFiletype type; /**< MOBIFiletype type */ + char extension[5]; /**< file extension */ + char mime_type[30]; /**< mime-type */ + } MOBIFileMeta; + + /** + @brief Encoding types in MOBI header (offset 28) + */ + typedef enum { + MOBI_CP1252 = 1252, /**< cp-1252 encoding */ + MOBI_UTF8 = 65001, /**< utf-8 encoding */ + MOBI_UTF16 = 65002, /**< utf-16 encoding */ + } MOBIEncoding; + + /** @} */ + + /** + @defgroup raw_structs Exported structures for the raw, unparsed records metadata and data + @{ + */ + + /** + @brief Header of palmdoc database file + */ + typedef struct { + char name[33]; /**< 0: Database name, zero terminated, trimmed title (+author) */ + uint16_t attributes; /**< 32: Attributes bitfield, PALMDB_ATTRIBUTE_DEFAULT */ + uint16_t version; /**< 34: File version, PALMDB_VERSION_DEFAULT */ + uint32_t ctime; /**< 36: Creation time */ + uint32_t mtime; /**< 40: Modification time */ + uint32_t btime; /**< 44: Backup time */ + uint32_t mod_num; /**< 48: Modification number, PALMDB_MODNUM_DEFAULT */ + uint32_t appinfo_offset; /**< 52: Offset to application info (if present) or zero, PALMDB_APPINFO_DEFAULT */ + uint32_t sortinfo_offset; /**< 56: Offset to sort info (if present) or zero, PALMDB_SORTINFO_DEFAULT */ + char type[5]; /**< 60: Database type, zero terminated, PALMDB_TYPE_DEFAULT */ + char creator[5]; /**< 64: Creator type, zero terminated, PALMDB_CREATOR_DEFAULT */ + uint32_t uid; /**< 68: Used internally to identify record */ + uint32_t next_rec; /**< 72: Used only when database is loaded into memory, PALMDB_NEXTREC_DEFAULT */ + uint16_t rec_count; /**< 76: Number of records in the file */ + } MOBIPdbHeader; + + /** + @brief Metadata and data of a record. All records form a linked list. + */ + typedef struct MOBIPdbRecord { + uint32_t offset; /**< Offset of the record data from the start of the database */ + size_t size; /**< Calculated size of the record data */ + uint8_t attributes; /**< Record attributes */ + uint32_t uid; /**< Record unique id, usually sequential even numbers */ + unsigned char *data; /**< Record data */ + struct MOBIPdbRecord *next; /**< Pointer to the next record or NULL */ + } MOBIPdbRecord; + + /** + @brief Metadata and data of a EXTH record. All records form a linked list. + */ + typedef struct MOBIExthHeader { + uint32_t tag; /**< Record tag */ + uint32_t size; /**< Data size */ + void *data; /**< Record data */ + struct MOBIExthHeader *next; /**< Pointer to the next record or NULL */ + } MOBIExthHeader; + + /** + @brief EXTH tag metadata + */ + typedef struct { + MOBIExthTag tag; /**< Record tag id */ + MOBIExthType type; /**< EXTH_NUMERIC, EXTH_STRING or EXTH_BINARY */ + char *name; /**< Tag name */ + } MOBIExthMeta; + + /** + @brief Header of the Record 0 meta-record + */ + typedef struct { + /* PalmDOC header (extended), offset 0, length 16 */ + uint16_t compression_type; /**< 0; 1 == no compression, 2 = PalmDOC compression, 17480 = HUFF/CDIC compression */ + /* uint16_t unused; // 2; 0 */ + uint32_t text_length; /**< 4; uncompressed length of the entire text of the book */ + uint16_t text_record_count; /**< 8; number of PDB records used for the text of the book */ + uint16_t text_record_size; /**< 10; maximum size of each record containing text, always 4096 */ + uint16_t encryption_type; /**< 12; 0 == no encryption, 1 = Old Mobipocket Encryption, 2 = Mobipocket Encryption */ + uint16_t unknown1; /**< 14; usually 0 */ + } MOBIRecord0Header; + + /** + @brief MOBI header which follows Record 0 header + + All MOBI header fields are pointers. Some fields are not present in the header, then the pointer is NULL. + */ + typedef struct { + /* MOBI header, offset 16 */ + char mobi_magic[5]; /**< 16: M O B I { 77, 79, 66, 73 }, zero terminated */ + uint32_t *header_length; /**< 20: the length of the MOBI header, including the previous 4 bytes */ + uint32_t *mobi_type; /**< 24: mobipocket file type */ + MOBIEncoding *text_encoding; /**< 28: 1252 = CP1252, 65001 = UTF-8 */ + uint32_t *uid; /**< 32: unique id */ + uint32_t *version; /**< 36: mobipocket format */ + uint32_t *orth_index; /**< 40: section number of orthographic meta index. MOBI_NOTSET if index is not available. */ + uint32_t *infl_index; /**< 44: section number of inflection meta index. MOBI_NOTSET if index is not available. */ + uint32_t *names_index; /**< 48: section number of names meta index. MOBI_NOTSET if index is not available. */ + uint32_t *keys_index; /**< 52: section number of keys meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra0_index; /**< 56: section number of extra 0 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra1_index; /**< 60: section number of extra 1 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra2_index; /**< 64: section number of extra 2 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra3_index; /**< 68: section number of extra 3 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra4_index; /**< 72: section number of extra 4 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *extra5_index; /**< 76: section number of extra 5 meta index. MOBI_NOTSET if index is not available. */ + uint32_t *non_text_index; /**< 80: first record number (starting with 0) that's not the book's text */ + uint32_t *full_name_offset; /**< 84: offset in record 0 (not from start of file) of the full name of the book */ + uint32_t *full_name_length; /**< 88: length of the full name */ + uint32_t *locale; /**< 92: first byte is main language: 09 = English, next byte is dialect, 08 = British, 04 = US */ + uint32_t *dict_input_lang; /**< 96: input language for a dictionary */ + uint32_t *dict_output_lang; /**< 100: output language for a dictionary */ + uint32_t *min_version; /**< 104: minimum mobipocket version support needed to read this file. */ + uint32_t *image_index; /**< 108: first record number (starting with 0) that contains an image (sequential) */ + uint32_t *huff_rec_index; /**< 112: first huffman compression record */ + uint32_t *huff_rec_count; /**< 116: huffman compression records count */ + uint32_t *datp_rec_index; /**< 120: section number of DATP record */ + uint32_t *datp_rec_count; /**< 124: DATP records count */ + uint32_t *exth_flags; /**< 128: bitfield. if bit 6 (0x40) is set, then there's an EXTH record */ + /* 32 unknown bytes, usually 0, related to encryption and unknown6 */ + /* unknown2 */ + /* unknown3 */ + /* unknown4 */ + /* unknown5 */ + uint32_t *unknown6; /**< 164: use MOBI_NOTSET , related to encryption*/ + uint32_t *drm_offset; /**< 168: offset to DRM key info in DRMed files. MOBI_NOTSET if no DRM */ + uint32_t *drm_count; /**< 172: number of entries in DRM info */ + uint32_t *drm_size; /**< 176: number of bytes in DRM info */ + uint32_t *drm_flags; /**< 180: some flags concerning DRM info, bit 0 set if password encryption */ + /* 8 unknown bytes 0? */ + /* unknown7 */ + /* unknown8 */ + uint16_t *first_text_index; /**< 192: section number of first text record */ + uint16_t *last_text_index; /**< 194: */ + uint32_t *fdst_index; /**< 192 (KF8) section number of FDST record */ + //uint32_t *unknown9; /**< 196: */ + uint32_t *fdst_section_count; /**< 196 (KF8) */ + uint32_t *fcis_index; /**< 200: section number of FCIS record */ + uint32_t *fcis_count; /**< 204: FCIS records count */ + uint32_t *flis_index; /**< 208: section number of FLIS record */ + uint32_t *flis_count; /**< 212: FLIS records count */ + uint32_t *unknown10; /**< 216: */ + uint32_t *unknown11; /**< 220: */ + uint32_t *srcs_index; /**< 224: section number of SRCS record */ + uint32_t *srcs_count; /**< 228: SRCS records count */ + uint32_t *unknown12; /**< 232: */ + uint32_t *unknown13; /**< 236: */ + /* uint16_t fill 0 */ + uint16_t *extra_flags; /**< 242: extra flags */ + uint32_t *ncx_index; /**< 244: section number of NCX record */ + uint32_t *unknown14; /**< 248: */ + uint32_t *fragment_index; /**< 248 (KF8) section number of fragments record */ + uint32_t *unknown15; /**< 252: */ + uint32_t *skeleton_index; /**< 252 (KF8) section number of SKEL record */ + uint32_t *datp_index; /**< 256: section number of DATP record */ + uint32_t *unknown16; /**< 260: */ + uint32_t *guide_index; /**< 260 (KF8) section number of guide record */ + uint32_t *unknown17; /**< 264: */ + uint32_t *unknown18; /**< 268: */ + uint32_t *unknown19; /**< 272: */ + uint32_t *unknown20; /**< 276: */ + char *full_name; /**< variable offset (full_name_offset): full name */ + } MOBIMobiHeader; + + /** + @brief Main structure holding all metadata and unparsed records data + + In case of hybrid KF7/KF8 file there are two Records 0. + In such case MOBIData is a circular linked list of two independent records, one structure per each Record 0 header. + Records data (MOBIPdbRecord structure) is not duplicated in such case - each struct holds same pointers to all records data. + */ + typedef struct MOBIData { + bool use_kf8; /**< Flag: if set to true (default), KF8 part of hybrid file is parsed, if false - KF7 part will be parsed */ + uint32_t kf8_boundary_offset; /**< Set to KF8 boundary rec number if present, otherwise: MOBI_NOTSET */ + unsigned char *drm_key; /**< @deprecated Will be removed in future versions */ + MOBIPdbHeader *ph; /**< Palmdoc database header structure or NULL if not loaded */ + MOBIRecord0Header *rh; /**< Record0 header structure or NULL if not loaded */ + MOBIMobiHeader *mh; /**< MOBI header structure or NULL if not loaded */ + MOBIExthHeader *eh; /**< Linked list of EXTH records or NULL if not loaded */ + MOBIPdbRecord *rec; /**< Linked list of palmdoc database records or NULL if not loaded */ + struct MOBIData *next; /**< Pointer to the other part of hybrid file or NULL if not a hybrid file */ + void *internals; /**< Used internally*/ + } MOBIData; + + /** @} */ // end of raw_structs group + + /** + @defgroup parsed_structs Exported structures for the parsed records metadata and data + @{ + */ + + /** + @brief Parsed FDST record + + FDST record contains offsets of main sections in RAWML - raw text data. + The sections are usually html part, css parts, svg part. + */ + typedef struct { + size_t fdst_section_count; /**< Number of main sections */ + uint32_t *fdst_section_starts; /**< Array of section start offsets */ + uint32_t *fdst_section_ends; /**< Array of section end offsets */ + } MOBIFdst; + + /** + @brief Parsed tag for an index entry + */ + typedef struct { + size_t tagid; /**< Tag id */ + size_t tagvalues_count; /**< Number of tag values */ + uint32_t *tagvalues; /**< Array of tag values */ + } MOBIIndexTag; + + /** + @brief Parsed INDX index entry + */ + typedef struct { + char *label; /**< Entry string, zero terminated */ + size_t tags_count; /**< Number of tags */ + MOBIIndexTag *tags; /**< Array of tags */ + } MOBIIndexEntry; + + /** + @brief Parsed INDX record + */ + typedef struct { + size_t type; /**< Index type: 0 - normal, 2 - inflection */ + size_t entries_count; /**< Index entries count */ + MOBIEncoding encoding; /**< Index encoding */ + size_t total_entries_count; /**< Total index entries count */ + size_t ordt_offset; /**< ORDT offset */ + size_t ligt_offset; /**< LIGT offset */ + size_t ligt_entries_count; /**< LIGT index entries count */ + size_t cncx_records_count; /**< Number of compiled NCX records */ + MOBIPdbRecord *cncx_record; /**< Link to CNCX record */ + MOBIIndexEntry *entries; /**< Index entries array */ + char *orth_index_name; /**< Orth index name */ + } MOBIIndx; + + /** + @brief Reconstructed source file. + + All file parts are organized in a linked list. + */ + typedef struct MOBIPart { + size_t uid; /**< Unique id */ + MOBIFiletype type; /**< File type */ + size_t size; /**< File size */ + unsigned char *data; /**< File data */ + struct MOBIPart *next; /**< Pointer to next part or NULL */ + } MOBIPart; + + /** + @brief Main structure containing reconstructed source parts and indices + */ + typedef struct { + size_t version; /**< Version of Mobipocket document */ + MOBIFdst *fdst; /**< Parsed FDST record or NULL if not present */ + MOBIIndx *skel; /**< Parsed skeleton index or NULL if not present */ + MOBIIndx *frag; /**< Parsed fragments index or NULL if not present */ + MOBIIndx *guide; /**< Parsed guide index or NULL if not present */ + MOBIIndx *ncx; /**< Parsed NCX index or NULL if not present */ + MOBIIndx *orth; /**< Parsed orth index or NULL if not present */ + MOBIIndx *infl; /**< Parsed infl index or NULL if not present */ + MOBIPart *flow; /**< Linked list of reconstructed main flow parts or NULL if not present */ + MOBIPart *markup; /**< Linked list of reconstructed markup files or NULL if not present */ + MOBIPart *resources; /**< Linked list of reconstructed resources files or NULL if not present */ + } MOBIRawml; + + /** @} */ // end of parsed_structs group + + /** + @defgroup mobi_export Functions exported by the library + @{ + */ + MOBI_EXPORT const char * mobi_version(void); + MOBI_EXPORT MOBI_RET mobi_load_file(MOBIData *m, FILE *file); + MOBI_EXPORT MOBI_RET mobi_load_filename(MOBIData *m, const char *path); + + MOBI_EXPORT MOBIData * mobi_init(void); + MOBI_EXPORT void mobi_free(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_parse_kf7(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_parse_kf8(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_parse_rawml(MOBIRawml *rawml, const MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_parse_rawml_opt(MOBIRawml *rawml, const MOBIData *m, bool parse_toc, bool parse_dict, bool reconstruct); + + MOBI_EXPORT MOBI_RET mobi_get_rawml(const MOBIData *m, char *text, size_t *len); + MOBI_EXPORT MOBI_RET mobi_dump_rawml(const MOBIData *m, FILE *file); + MOBI_EXPORT MOBI_RET mobi_decode_font_resource(unsigned char **decoded_font, size_t *decoded_size, MOBIPart *part); + MOBI_EXPORT MOBI_RET mobi_decode_audio_resource(unsigned char **decoded_resource, size_t *decoded_size, MOBIPart *part); + MOBI_EXPORT MOBI_RET mobi_decode_video_resource(unsigned char **decoded_resource, size_t *decoded_size, MOBIPart *part); + MOBI_EXPORT MOBI_RET mobi_get_embedded_source(unsigned char **data, size_t *size, const MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_get_embedded_log(unsigned char **data, size_t *size, const MOBIData *m); + + MOBI_EXPORT MOBIPdbRecord * mobi_get_record_by_uid(const MOBIData *m, const size_t uid); + MOBI_EXPORT MOBIPdbRecord * mobi_get_record_by_seqnumber(const MOBIData *m, const size_t uid); + MOBI_EXPORT MOBIPart * mobi_get_flow_by_uid(const MOBIRawml *rawml, const size_t uid); + MOBI_EXPORT MOBIPart * mobi_get_flow_by_fid(const MOBIRawml *rawml, const char *fid); + MOBI_EXPORT MOBIPart * mobi_get_resource_by_uid(const MOBIRawml *rawml, const size_t uid); + MOBI_EXPORT MOBIPart * mobi_get_resource_by_fid(const MOBIRawml *rawml, const char *fid); + MOBI_EXPORT MOBIPart * mobi_get_part_by_uid(const MOBIRawml *rawml, const size_t uid); + MOBI_EXPORT MOBI_RET mobi_get_fullname(const MOBIData *m, char *fullname, const size_t len); + MOBI_EXPORT size_t mobi_get_first_resource_record(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_text_maxsize(const MOBIData *m); + MOBI_EXPORT uint16_t mobi_get_textrecord_maxsize(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_kf8offset(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_kf8boundary_seqnumber(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_record_extrasize(const MOBIPdbRecord *record, const uint16_t flags); + MOBI_EXPORT size_t mobi_get_record_mb_extrasize(const MOBIPdbRecord *record, const uint16_t flags); + MOBI_EXPORT size_t mobi_get_fileversion(const MOBIData *m); + MOBI_EXPORT size_t mobi_get_fdst_record_number(const MOBIData *m); + MOBI_EXPORT MOBIExthHeader * mobi_get_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag); + MOBI_EXPORT MOBIExthHeader * mobi_next_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag, MOBIExthHeader **start); + MOBI_EXPORT MOBI_RET mobi_delete_exthrecord_by_tag(MOBIData *m, const MOBIExthTag tag); + MOBI_EXPORT MOBI_RET mobi_add_exthrecord(MOBIData *m, const MOBIExthTag tag, const uint32_t size, const void *value); + MOBI_EXPORT MOBIExthMeta mobi_get_exthtagmeta_by_tag(const MOBIExthTag tag); + MOBI_EXPORT MOBIFileMeta mobi_get_filemeta_by_type(const MOBIFiletype type); + MOBI_EXPORT uint32_t mobi_decode_exthvalue(const unsigned char *data, const size_t size); + MOBI_EXPORT char * mobi_decode_exthstring(const MOBIData *m, const unsigned char *data, const size_t size); + MOBI_EXPORT struct tm * mobi_pdbtime_to_time(const long pdb_time); + MOBI_EXPORT const char * mobi_get_locale_string(const uint32_t locale); + MOBI_EXPORT size_t mobi_get_locale_number(const char *locale_string); + MOBI_EXPORT uint32_t mobi_get_orth_entry_offset(const MOBIIndexEntry *entry); + MOBI_EXPORT uint32_t mobi_get_orth_entry_length(const MOBIIndexEntry *entry); + MOBI_EXPORT MOBI_RET mobi_remove_hybrid_part(MOBIData *m, const bool remove_kf8); + + MOBI_EXPORT bool mobi_exists_mobiheader(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_fdst(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_skel_indx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_frag_indx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_guide_indx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_ncx(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_orth(const MOBIData *m); + MOBI_EXPORT bool mobi_exists_infl(const MOBIData *m); + MOBI_EXPORT bool mobi_is_hybrid(const MOBIData *m); + MOBI_EXPORT bool mobi_is_encrypted(const MOBIData *m); + MOBI_EXPORT bool mobi_is_mobipocket(const MOBIData *m); + MOBI_EXPORT bool mobi_is_dictionary(const MOBIData *m); + MOBI_EXPORT bool mobi_is_kf8(const MOBIData *m); + MOBI_EXPORT bool mobi_is_replica(const MOBIData *m); + MOBI_EXPORT bool mobi_is_rawml_kf8(const MOBIRawml *rawml); + MOBI_EXPORT MOBIRawml * mobi_init_rawml(const MOBIData *m); + MOBI_EXPORT void mobi_free_rawml(MOBIRawml *rawml); + + MOBI_EXPORT char * mobi_meta_get_title(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_author(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_publisher(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_imprint(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_description(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_isbn(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_subject(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_publishdate(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_review(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_contributor(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_copyright(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_asin(const MOBIData *m); + MOBI_EXPORT char * mobi_meta_get_language(const MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_title(MOBIData *m, const char *title); + MOBI_EXPORT MOBI_RET mobi_meta_add_title(MOBIData *m, const char *title); + MOBI_EXPORT MOBI_RET mobi_meta_delete_title(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_author(MOBIData *m, const char *author); + MOBI_EXPORT MOBI_RET mobi_meta_add_author(MOBIData *m, const char *author); + MOBI_EXPORT MOBI_RET mobi_meta_delete_author(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_publisher(MOBIData *m, const char *publisher); + MOBI_EXPORT MOBI_RET mobi_meta_add_publisher(MOBIData *m, const char *publisher); + MOBI_EXPORT MOBI_RET mobi_meta_delete_publisher(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_imprint(MOBIData *m, const char *imprint); + MOBI_EXPORT MOBI_RET mobi_meta_add_imprint(MOBIData *m, const char *imprint); + MOBI_EXPORT MOBI_RET mobi_meta_delete_imprint(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_description(MOBIData *m, const char *description); + MOBI_EXPORT MOBI_RET mobi_meta_add_description(MOBIData *m, const char *description); + MOBI_EXPORT MOBI_RET mobi_meta_delete_description(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_isbn(MOBIData *m, const char *isbn); + MOBI_EXPORT MOBI_RET mobi_meta_add_isbn(MOBIData *m, const char *isbn); + MOBI_EXPORT MOBI_RET mobi_meta_delete_isbn(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_subject(MOBIData *m, const char *subject); + MOBI_EXPORT MOBI_RET mobi_meta_add_subject(MOBIData *m, const char *subject); + MOBI_EXPORT MOBI_RET mobi_meta_delete_subject(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_publishdate(MOBIData *m, const char *publishdate); + MOBI_EXPORT MOBI_RET mobi_meta_add_publishdate(MOBIData *m, const char *publishdate); + MOBI_EXPORT MOBI_RET mobi_meta_delete_publishdate(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_review(MOBIData *m, const char *review); + MOBI_EXPORT MOBI_RET mobi_meta_add_review(MOBIData *m, const char *review); + MOBI_EXPORT MOBI_RET mobi_meta_delete_review(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_contributor(MOBIData *m, const char *contributor); + MOBI_EXPORT MOBI_RET mobi_meta_add_contributor(MOBIData *m, const char *contributor); + MOBI_EXPORT MOBI_RET mobi_meta_delete_contributor(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_copyright(MOBIData *m, const char *copyright); + MOBI_EXPORT MOBI_RET mobi_meta_add_copyright(MOBIData *m, const char *copyright); + MOBI_EXPORT MOBI_RET mobi_meta_delete_copyright(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_asin(MOBIData *m, const char *asin); + MOBI_EXPORT MOBI_RET mobi_meta_add_asin(MOBIData *m, const char *asin); + MOBI_EXPORT MOBI_RET mobi_meta_delete_asin(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_meta_set_language(MOBIData *m, const char *language); + MOBI_EXPORT MOBI_RET mobi_meta_add_language(MOBIData *m, const char *language); + MOBI_EXPORT MOBI_RET mobi_meta_delete_language(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_drm_setkey(MOBIData *m, const char *pid); + MOBI_EXPORT MOBI_RET mobi_drm_setkey_serial(MOBIData *m, const char *serial); + MOBI_EXPORT MOBI_RET mobi_drm_addvoucher(MOBIData *m, const char *serial, const time_t valid_from, const time_t valid_to, + const MOBIExthTag *tamperkeys, const size_t tamperkeys_count); + MOBI_EXPORT MOBI_RET mobi_drm_delkey(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_drm_decrypt(MOBIData *m); + MOBI_EXPORT MOBI_RET mobi_drm_encrypt(MOBIData *m); + + MOBI_EXPORT MOBI_RET mobi_write_file(FILE *file, MOBIData *m); + /** @} */ // end of mobi_export group + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/.signature.p7s b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/.signature.p7s new file mode 100644 index 0000000..1082457 Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/.signature.p7s differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/build/native/libxml2-vc140-static-32_64.targets b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/build/native/libxml2-vc140-static-32_64.targets new file mode 100644 index 0000000..a60601a --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/build/native/libxml2-vc140-static-32_64.targets @@ -0,0 +1,13 @@ + + + + + $(MSBuildThisFileDirectory)..\..\lib\native\include\;%(AdditionalIncludeDirectories) + + + $(MSBuildThisFileDirectory)..\..\lib\native\libs\x64\static\$(Configuration);%(AdditionalLibraryDirectories) + $(MSBuildThisFileDirectory)..\..\lib\native\libs\x86\static\$(Configuration);%(AdditionalLibraryDirectories) + libxml2.lib;%(AdditionalDependencies) + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/DOCBparser.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/DOCBparser.h new file mode 100644 index 0000000..9394fa7 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/DOCBparser.h @@ -0,0 +1,96 @@ +/* + * Summary: old DocBook SGML parser + * Description: interface for a DocBook SGML non-verifying parser + * This code is DEPRECATED, and should not be used anymore. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __DOCB_PARSER_H__ +#define __DOCB_PARSER_H__ +#include + +#ifdef LIBXML_DOCB_ENABLED + +#include +#include + +#ifndef IN_LIBXML +#ifdef __GNUC__ +#warning "The DOCBparser module has been deprecated in libxml2-2.6.0" +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Most of the back-end structures from XML and SGML are shared. + */ +typedef xmlParserCtxt docbParserCtxt; +typedef xmlParserCtxtPtr docbParserCtxtPtr; +typedef xmlSAXHandler docbSAXHandler; +typedef xmlSAXHandlerPtr docbSAXHandlerPtr; +typedef xmlParserInput docbParserInput; +typedef xmlParserInputPtr docbParserInputPtr; +typedef xmlDocPtr docbDocPtr; + +/* + * There is only few public functions. + */ +XMLPUBFUN int XMLCALL + docbEncodeEntities(unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen, int quoteChar); + +XMLPUBFUN docbDocPtr XMLCALL + docbSAXParseDoc (xmlChar *cur, + const char *encoding, + docbSAXHandlerPtr sax, + void *userData); +XMLPUBFUN docbDocPtr XMLCALL + docbParseDoc (xmlChar *cur, + const char *encoding); +XMLPUBFUN docbDocPtr XMLCALL + docbSAXParseFile (const char *filename, + const char *encoding, + docbSAXHandlerPtr sax, + void *userData); +XMLPUBFUN docbDocPtr XMLCALL + docbParseFile (const char *filename, + const char *encoding); + +/** + * Interfaces for the Push mode. + */ +XMLPUBFUN void XMLCALL + docbFreeParserCtxt (docbParserCtxtPtr ctxt); +XMLPUBFUN docbParserCtxtPtr XMLCALL + docbCreatePushParserCtxt(docbSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + docbParseChunk (docbParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +XMLPUBFUN docbParserCtxtPtr XMLCALL + docbCreateFileParserCtxt(const char *filename, + const char *encoding); +XMLPUBFUN int XMLCALL + docbParseDocument (docbParserCtxtPtr ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_DOCB_ENABLED */ + +#endif /* __DOCB_PARSER_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/HTMLparser.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/HTMLparser.h new file mode 100644 index 0000000..551186c --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/HTMLparser.h @@ -0,0 +1,306 @@ +/* + * Summary: interface for an HTML 4.0 non-verifying parser + * Description: this module implements an HTML 4.0 non-verifying parser + * with API compatible with the XML parser ones. It should + * be able to parse "real world" HTML, even if severely + * broken from a specification point of view. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __HTML_PARSER_H__ +#define __HTML_PARSER_H__ +#include +#include + +#ifdef LIBXML_HTML_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Most of the back-end structures from XML and HTML are shared. + */ +typedef xmlParserCtxt htmlParserCtxt; +typedef xmlParserCtxtPtr htmlParserCtxtPtr; +typedef xmlParserNodeInfo htmlParserNodeInfo; +typedef xmlSAXHandler htmlSAXHandler; +typedef xmlSAXHandlerPtr htmlSAXHandlerPtr; +typedef xmlParserInput htmlParserInput; +typedef xmlParserInputPtr htmlParserInputPtr; +typedef xmlDocPtr htmlDocPtr; +typedef xmlNodePtr htmlNodePtr; + +/* + * Internal description of an HTML element, representing HTML 4.01 + * and XHTML 1.0 (which share the same structure). + */ +typedef struct _htmlElemDesc htmlElemDesc; +typedef htmlElemDesc *htmlElemDescPtr; +struct _htmlElemDesc { + const char *name; /* The tag name */ + char startTag; /* Whether the start tag can be implied */ + char endTag; /* Whether the end tag can be implied */ + char saveEndTag; /* Whether the end tag should be saved */ + char empty; /* Is this an empty element ? */ + char depr; /* Is this a deprecated element ? */ + char dtd; /* 1: only in Loose DTD, 2: only Frameset one */ + char isinline; /* is this a block 0 or inline 1 element */ + const char *desc; /* the description */ + +/* NRK Jan.2003 + * New fields encapsulating HTML structure + * + * Bugs: + * This is a very limited representation. It fails to tell us when + * an element *requires* subelements (we only have whether they're + * allowed or not), and it doesn't tell us where CDATA and PCDATA + * are allowed. Some element relationships are not fully represented: + * these are flagged with the word MODIFIER + */ + const char** subelts; /* allowed sub-elements of this element */ + const char* defaultsubelt; /* subelement for suggested auto-repair + if necessary or NULL */ + const char** attrs_opt; /* Optional Attributes */ + const char** attrs_depr; /* Additional deprecated attributes */ + const char** attrs_req; /* Required attributes */ +}; + +/* + * Internal description of an HTML entity. + */ +typedef struct _htmlEntityDesc htmlEntityDesc; +typedef htmlEntityDesc *htmlEntityDescPtr; +struct _htmlEntityDesc { + unsigned int value; /* the UNICODE value for the character */ + const char *name; /* The entity name */ + const char *desc; /* the description */ +}; + +/* + * There is only few public functions. + */ +XMLPUBFUN const htmlElemDesc * XMLCALL + htmlTagLookup (const xmlChar *tag); +XMLPUBFUN const htmlEntityDesc * XMLCALL + htmlEntityLookup(const xmlChar *name); +XMLPUBFUN const htmlEntityDesc * XMLCALL + htmlEntityValueLookup(unsigned int value); + +XMLPUBFUN int XMLCALL + htmlIsAutoClosed(htmlDocPtr doc, + htmlNodePtr elem); +XMLPUBFUN int XMLCALL + htmlAutoCloseTag(htmlDocPtr doc, + const xmlChar *name, + htmlNodePtr elem); +XMLPUBFUN const htmlEntityDesc * XMLCALL + htmlParseEntityRef(htmlParserCtxtPtr ctxt, + const xmlChar **str); +XMLPUBFUN int XMLCALL + htmlParseCharRef(htmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + htmlParseElement(htmlParserCtxtPtr ctxt); + +XMLPUBFUN htmlParserCtxtPtr XMLCALL + htmlNewParserCtxt(void); + +XMLPUBFUN htmlParserCtxtPtr XMLCALL + htmlCreateMemoryParserCtxt(const char *buffer, + int size); + +XMLPUBFUN int XMLCALL + htmlParseDocument(htmlParserCtxtPtr ctxt); +XMLPUBFUN htmlDocPtr XMLCALL + htmlSAXParseDoc (xmlChar *cur, + const char *encoding, + htmlSAXHandlerPtr sax, + void *userData); +XMLPUBFUN htmlDocPtr XMLCALL + htmlParseDoc (xmlChar *cur, + const char *encoding); +XMLPUBFUN htmlDocPtr XMLCALL + htmlSAXParseFile(const char *filename, + const char *encoding, + htmlSAXHandlerPtr sax, + void *userData); +XMLPUBFUN htmlDocPtr XMLCALL + htmlParseFile (const char *filename, + const char *encoding); +XMLPUBFUN int XMLCALL + UTF8ToHtml (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +XMLPUBFUN int XMLCALL + htmlEncodeEntities(unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen, int quoteChar); +XMLPUBFUN int XMLCALL + htmlIsScriptAttribute(const xmlChar *name); +XMLPUBFUN int XMLCALL + htmlHandleOmittedElem(int val); + +#ifdef LIBXML_PUSH_ENABLED +/** + * Interfaces for the Push mode. + */ +XMLPUBFUN htmlParserCtxtPtr XMLCALL + htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + htmlParseChunk (htmlParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +#endif /* LIBXML_PUSH_ENABLED */ + +XMLPUBFUN void XMLCALL + htmlFreeParserCtxt (htmlParserCtxtPtr ctxt); + +/* + * New set of simpler/more flexible APIs + */ +/** + * xmlParserOption: + * + * This is the set of XML parser options that can be passed down + * to the xmlReadDoc() and similar calls. + */ +typedef enum { + HTML_PARSE_RECOVER = 1<<0, /* Relaxed parsing */ + HTML_PARSE_NODEFDTD = 1<<2, /* do not default a doctype if not found */ + HTML_PARSE_NOERROR = 1<<5, /* suppress error reports */ + HTML_PARSE_NOWARNING= 1<<6, /* suppress warning reports */ + HTML_PARSE_PEDANTIC = 1<<7, /* pedantic error reporting */ + HTML_PARSE_NOBLANKS = 1<<8, /* remove blank nodes */ + HTML_PARSE_NONET = 1<<11,/* Forbid network access */ + HTML_PARSE_NOIMPLIED= 1<<13,/* Do not add implied html/body... elements */ + HTML_PARSE_COMPACT = 1<<16,/* compact small text nodes */ + HTML_PARSE_IGNORE_ENC=1<<21 /* ignore internal document encoding hint */ +} htmlParserOption; + +XMLPUBFUN void XMLCALL + htmlCtxtReset (htmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + htmlCtxtUseOptions (htmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlReadDoc (const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlReadFile (const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlReadMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlReadFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlReadIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlCtxtReadDoc (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlCtxtReadFile (xmlParserCtxtPtr ctxt, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlCtxtReadMemory (xmlParserCtxtPtr ctxt, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlCtxtReadFd (xmlParserCtxtPtr ctxt, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN htmlDocPtr XMLCALL + htmlCtxtReadIO (xmlParserCtxtPtr ctxt, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +/* NRK/Jan2003: further knowledge of HTML structure + */ +typedef enum { + HTML_NA = 0 , /* something we don't check at all */ + HTML_INVALID = 0x1 , + HTML_DEPRECATED = 0x2 , + HTML_VALID = 0x4 , + HTML_REQUIRED = 0xc /* VALID bit set so ( & HTML_VALID ) is TRUE */ +} htmlStatus ; + +/* Using htmlElemDesc rather than name here, to emphasise the fact + that otherwise there's a lookup overhead +*/ +XMLPUBFUN htmlStatus XMLCALL htmlAttrAllowed(const htmlElemDesc*, const xmlChar*, int) ; +XMLPUBFUN int XMLCALL htmlElementAllowedHere(const htmlElemDesc*, const xmlChar*) ; +XMLPUBFUN htmlStatus XMLCALL htmlElementStatusHere(const htmlElemDesc*, const htmlElemDesc*) ; +XMLPUBFUN htmlStatus XMLCALL htmlNodeStatus(const htmlNodePtr, int) ; +/** + * htmlDefaultSubelement: + * @elt: HTML element + * + * Returns the default subelement for this element + */ +#define htmlDefaultSubelement(elt) elt->defaultsubelt +/** + * htmlElementAllowedHereDesc: + * @parent: HTML parent element + * @elt: HTML element + * + * Checks whether an HTML element description may be a + * direct child of the specified element. + * + * Returns 1 if allowed; 0 otherwise. + */ +#define htmlElementAllowedHereDesc(parent,elt) \ + htmlElementAllowedHere((parent), (elt)->name) +/** + * htmlRequiredAttrs: + * @elt: HTML element + * + * Returns the attributes required for the specified element. + */ +#define htmlRequiredAttrs(elt) (elt)->attrs_req + + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_HTML_ENABLED */ +#endif /* __HTML_PARSER_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/HTMLtree.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/HTMLtree.h new file mode 100644 index 0000000..c0e1103 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/HTMLtree.h @@ -0,0 +1,147 @@ +/* + * Summary: specific APIs to process HTML tree, especially serialization + * Description: this module implements a few function needed to process + * tree in an HTML specific way. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __HTML_TREE_H__ +#define __HTML_TREE_H__ + +#include +#include +#include +#include + +#ifdef LIBXML_HTML_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * HTML_TEXT_NODE: + * + * Macro. A text node in a HTML document is really implemented + * the same way as a text node in an XML document. + */ +#define HTML_TEXT_NODE XML_TEXT_NODE +/** + * HTML_ENTITY_REF_NODE: + * + * Macro. An entity reference in a HTML document is really implemented + * the same way as an entity reference in an XML document. + */ +#define HTML_ENTITY_REF_NODE XML_ENTITY_REF_NODE +/** + * HTML_COMMENT_NODE: + * + * Macro. A comment in a HTML document is really implemented + * the same way as a comment in an XML document. + */ +#define HTML_COMMENT_NODE XML_COMMENT_NODE +/** + * HTML_PRESERVE_NODE: + * + * Macro. A preserved node in a HTML document is really implemented + * the same way as a CDATA section in an XML document. + */ +#define HTML_PRESERVE_NODE XML_CDATA_SECTION_NODE +/** + * HTML_PI_NODE: + * + * Macro. A processing instruction in a HTML document is really implemented + * the same way as a processing instruction in an XML document. + */ +#define HTML_PI_NODE XML_PI_NODE + +XMLPUBFUN htmlDocPtr XMLCALL + htmlNewDoc (const xmlChar *URI, + const xmlChar *ExternalID); +XMLPUBFUN htmlDocPtr XMLCALL + htmlNewDocNoDtD (const xmlChar *URI, + const xmlChar *ExternalID); +XMLPUBFUN const xmlChar * XMLCALL + htmlGetMetaEncoding (htmlDocPtr doc); +XMLPUBFUN int XMLCALL + htmlSetMetaEncoding (htmlDocPtr doc, + const xmlChar *encoding); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + htmlDocDumpMemory (xmlDocPtr cur, + xmlChar **mem, + int *size); +XMLPUBFUN void XMLCALL + htmlDocDumpMemoryFormat (xmlDocPtr cur, + xmlChar **mem, + int *size, + int format); +XMLPUBFUN int XMLCALL + htmlDocDump (FILE *f, + xmlDocPtr cur); +XMLPUBFUN int XMLCALL + htmlSaveFile (const char *filename, + xmlDocPtr cur); +XMLPUBFUN int XMLCALL + htmlNodeDump (xmlBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN void XMLCALL + htmlNodeDumpFile (FILE *out, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN int XMLCALL + htmlNodeDumpFileFormat (FILE *out, + xmlDocPtr doc, + xmlNodePtr cur, + const char *encoding, + int format); +XMLPUBFUN int XMLCALL + htmlSaveFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN int XMLCALL + htmlSaveFileFormat (const char *filename, + xmlDocPtr cur, + const char *encoding, + int format); + +XMLPUBFUN void XMLCALL + htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + const char *encoding, + int format); +XMLPUBFUN void XMLCALL + htmlDocContentDumpOutput(xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN void XMLCALL + htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding, + int format); +XMLPUBFUN void XMLCALL + htmlNodeDumpOutput (xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + const char *encoding); + +#endif /* LIBXML_OUTPUT_ENABLED */ + +XMLPUBFUN int XMLCALL + htmlIsBooleanAttr (const xmlChar *name); + + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_HTML_ENABLED */ + +#endif /* __HTML_TREE_H__ */ + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/SAX.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/SAX.h new file mode 100644 index 0000000..20093ce --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/SAX.h @@ -0,0 +1,173 @@ +/* + * Summary: Old SAX version 1 handler, deprecated + * Description: DEPRECATED set of SAX version 1 interfaces used to + * build the DOM tree. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SAX_H__ +#define __XML_SAX_H__ + +#include +#include +#include +#include +#include + +#ifdef LIBXML_LEGACY_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN const xmlChar * XMLCALL + getPublicId (void *ctx); +XMLPUBFUN const xmlChar * XMLCALL + getSystemId (void *ctx); +XMLPUBFUN void XMLCALL + setDocumentLocator (void *ctx, + xmlSAXLocatorPtr loc); + +XMLPUBFUN int XMLCALL + getLineNumber (void *ctx); +XMLPUBFUN int XMLCALL + getColumnNumber (void *ctx); + +XMLPUBFUN int XMLCALL + isStandalone (void *ctx); +XMLPUBFUN int XMLCALL + hasInternalSubset (void *ctx); +XMLPUBFUN int XMLCALL + hasExternalSubset (void *ctx); + +XMLPUBFUN void XMLCALL + internalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN void XMLCALL + externalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlEntityPtr XMLCALL + getEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + getParameterEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlParserInputPtr XMLCALL + resolveEntity (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +XMLPUBFUN void XMLCALL + entityDecl (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +XMLPUBFUN void XMLCALL + attributeDecl (void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +XMLPUBFUN void XMLCALL + elementDecl (void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + notationDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +XMLPUBFUN void XMLCALL + unparsedEntityDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +XMLPUBFUN void XMLCALL + startDocument (void *ctx); +XMLPUBFUN void XMLCALL + endDocument (void *ctx); +XMLPUBFUN void XMLCALL + attribute (void *ctx, + const xmlChar *fullname, + const xmlChar *value); +XMLPUBFUN void XMLCALL + startElement (void *ctx, + const xmlChar *fullname, + const xmlChar **atts); +XMLPUBFUN void XMLCALL + endElement (void *ctx, + const xmlChar *name); +XMLPUBFUN void XMLCALL + reference (void *ctx, + const xmlChar *name); +XMLPUBFUN void XMLCALL + characters (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + ignorableWhitespace (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + processingInstruction (void *ctx, + const xmlChar *target, + const xmlChar *data); +XMLPUBFUN void XMLCALL + globalNamespace (void *ctx, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + setNamespace (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlNsPtr XMLCALL + getNamespace (void *ctx); +XMLPUBFUN int XMLCALL + checkNamespace (void *ctx, + xmlChar *nameSpace); +XMLPUBFUN void XMLCALL + namespaceDecl (void *ctx, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + comment (void *ctx, + const xmlChar *value); +XMLPUBFUN void XMLCALL + cdataBlock (void *ctx, + const xmlChar *value, + int len); + +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN void XMLCALL + initxmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr, + int warning); +#ifdef LIBXML_HTML_ENABLED +XMLPUBFUN void XMLCALL + inithtmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr); +#endif +#ifdef LIBXML_DOCB_ENABLED +XMLPUBFUN void XMLCALL + initdocbDefaultSAXHandler (xmlSAXHandlerV1 *hdlr); +#endif +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_LEGACY_ENABLED */ + +#endif /* __XML_SAX_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/SAX2.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/SAX2.h new file mode 100644 index 0000000..a55212e --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/SAX2.h @@ -0,0 +1,178 @@ +/* + * Summary: SAX2 parser interface used to build the DOM tree + * Description: those are the default SAX2 interfaces used by + * the library when building DOM tree. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SAX2_H__ +#define __XML_SAX2_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN const xmlChar * XMLCALL + xmlSAX2GetPublicId (void *ctx); +XMLPUBFUN const xmlChar * XMLCALL + xmlSAX2GetSystemId (void *ctx); +XMLPUBFUN void XMLCALL + xmlSAX2SetDocumentLocator (void *ctx, + xmlSAXLocatorPtr loc); + +XMLPUBFUN int XMLCALL + xmlSAX2GetLineNumber (void *ctx); +XMLPUBFUN int XMLCALL + xmlSAX2GetColumnNumber (void *ctx); + +XMLPUBFUN int XMLCALL + xmlSAX2IsStandalone (void *ctx); +XMLPUBFUN int XMLCALL + xmlSAX2HasInternalSubset (void *ctx); +XMLPUBFUN int XMLCALL + xmlSAX2HasExternalSubset (void *ctx); + +XMLPUBFUN void XMLCALL + xmlSAX2InternalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN void XMLCALL + xmlSAX2ExternalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlSAX2GetEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlSAX2GetParameterEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlSAX2ResolveEntity (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +XMLPUBFUN void XMLCALL + xmlSAX2EntityDecl (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +XMLPUBFUN void XMLCALL + xmlSAX2AttributeDecl (void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +XMLPUBFUN void XMLCALL + xmlSAX2ElementDecl (void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + xmlSAX2NotationDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +XMLPUBFUN void XMLCALL + xmlSAX2UnparsedEntityDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +XMLPUBFUN void XMLCALL + xmlSAX2StartDocument (void *ctx); +XMLPUBFUN void XMLCALL + xmlSAX2EndDocument (void *ctx); +#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ + defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) || \ + defined(LIBXML_LEGACY_ENABLED) +XMLPUBFUN void XMLCALL + xmlSAX2StartElement (void *ctx, + const xmlChar *fullname, + const xmlChar **atts); +XMLPUBFUN void XMLCALL + xmlSAX2EndElement (void *ctx, + const xmlChar *name); +#endif /* LIBXML_SAX1_ENABLED or LIBXML_HTML_ENABLED or LIBXML_LEGACY_ENABLED */ +XMLPUBFUN void XMLCALL + xmlSAX2StartElementNs (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes); +XMLPUBFUN void XMLCALL + xmlSAX2EndElementNs (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI); +XMLPUBFUN void XMLCALL + xmlSAX2Reference (void *ctx, + const xmlChar *name); +XMLPUBFUN void XMLCALL + xmlSAX2Characters (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + xmlSAX2IgnorableWhitespace (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + xmlSAX2ProcessingInstruction (void *ctx, + const xmlChar *target, + const xmlChar *data); +XMLPUBFUN void XMLCALL + xmlSAX2Comment (void *ctx, + const xmlChar *value); +XMLPUBFUN void XMLCALL + xmlSAX2CDataBlock (void *ctx, + const xmlChar *value, + int len); + +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlSAXDefaultVersion (int version); +#endif /* LIBXML_SAX1_ENABLED */ + +XMLPUBFUN int XMLCALL + xmlSAXVersion (xmlSAXHandler *hdlr, + int version); +XMLPUBFUN void XMLCALL + xmlSAX2InitDefaultSAXHandler (xmlSAXHandler *hdlr, + int warning); +#ifdef LIBXML_HTML_ENABLED +XMLPUBFUN void XMLCALL + xmlSAX2InitHtmlDefaultSAXHandler(xmlSAXHandler *hdlr); +XMLPUBFUN void XMLCALL + htmlDefaultSAXHandlerInit (void); +#endif +#ifdef LIBXML_DOCB_ENABLED +XMLPUBFUN void XMLCALL + xmlSAX2InitDocbDefaultSAXHandler(xmlSAXHandler *hdlr); +XMLPUBFUN void XMLCALL + docbDefaultSAXHandlerInit (void); +#endif +XMLPUBFUN void XMLCALL + xmlDefaultSAXHandlerInit (void); +#ifdef __cplusplus +} +#endif +#endif /* __XML_SAX2_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/c14n.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/c14n.h new file mode 100644 index 0000000..b8971d9 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/c14n.h @@ -0,0 +1,126 @@ +/* + * Summary: Provide Canonical XML and Exclusive XML Canonicalization + * Description: the c14n modules provides a + * + * "Canonical XML" implementation + * http://www.w3.org/TR/xml-c14n + * + * and an + * + * "Exclusive XML Canonicalization" implementation + * http://www.w3.org/TR/xml-exc-c14n + + * Copy: See Copyright for the status of this software. + * + * Author: Aleksey Sanin + */ +#ifndef __XML_C14N_H__ +#define __XML_C14N_H__ +#ifdef LIBXML_C14N_ENABLED +#ifdef LIBXML_OUTPUT_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include + +/* + * XML Canonicazation + * http://www.w3.org/TR/xml-c14n + * + * Exclusive XML Canonicazation + * http://www.w3.org/TR/xml-exc-c14n + * + * Canonical form of an XML document could be created if and only if + * a) default attributes (if any) are added to all nodes + * b) all character and parsed entity references are resolved + * In order to achive this in libxml2 the document MUST be loaded with + * following global setings: + * + * xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + * xmlSubstituteEntitiesDefault(1); + * + * or corresponding parser context setting: + * xmlParserCtxtPtr ctxt; + * + * ... + * ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + * ctxt->replaceEntities = 1; + * ... + */ + +/* + * xmlC14NMode: + * + * Predefined values for C14N modes + * + */ +typedef enum { + XML_C14N_1_0 = 0, /* Origianal C14N 1.0 spec */ + XML_C14N_EXCLUSIVE_1_0 = 1, /* Exclusive C14N 1.0 spec */ + XML_C14N_1_1 = 2 /* C14N 1.1 spec */ +} xmlC14NMode; + +XMLPUBFUN int XMLCALL + xmlC14NDocSaveTo (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlOutputBufferPtr buf); + +XMLPUBFUN int XMLCALL + xmlC14NDocDumpMemory (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlChar **doc_txt_ptr); + +XMLPUBFUN int XMLCALL + xmlC14NDocSave (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + const char* filename, + int compression); + + +/** + * This is the core C14N function + */ +/** + * xmlC14NIsVisibleCallback: + * @user_data: user data + * @node: the curent node + * @parent: the parent node + * + * Signature for a C14N callback on visible nodes + * + * Returns 1 if the node should be included + */ +typedef int (*xmlC14NIsVisibleCallback) (void* user_data, + xmlNodePtr node, + xmlNodePtr parent); + +XMLPUBFUN int XMLCALL + xmlC14NExecute (xmlDocPtr doc, + xmlC14NIsVisibleCallback is_visible_callback, + void* user_data, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlOutputBufferPtr buf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* LIBXML_C14N_ENABLED */ +#endif /* __XML_C14N_H__ */ + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/catalog.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/catalog.h new file mode 100644 index 0000000..5a13f51 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/catalog.h @@ -0,0 +1,182 @@ +/** + * Summary: interfaces to the Catalog handling system + * Description: the catalog module implements the support for + * XML Catalogs and SGML catalogs + * + * SGML Open Technical Resolution TR9401:1997. + * http://www.jclark.com/sp/catalog.htm + * + * XML Catalogs Working Draft 06 August 2001 + * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_CATALOG_H__ +#define __XML_CATALOG_H__ + +#include + +#include +#include +#include + +#ifdef LIBXML_CATALOG_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XML_CATALOGS_NAMESPACE: + * + * The namespace for the XML Catalogs elements. + */ +#define XML_CATALOGS_NAMESPACE \ + (const xmlChar *) "urn:oasis:names:tc:entity:xmlns:xml:catalog" +/** + * XML_CATALOG_PI: + * + * The specific XML Catalog Processing Instuction name. + */ +#define XML_CATALOG_PI \ + (const xmlChar *) "oasis-xml-catalog" + +/* + * The API is voluntarily limited to general cataloging. + */ +typedef enum { + XML_CATA_PREFER_NONE = 0, + XML_CATA_PREFER_PUBLIC = 1, + XML_CATA_PREFER_SYSTEM +} xmlCatalogPrefer; + +typedef enum { + XML_CATA_ALLOW_NONE = 0, + XML_CATA_ALLOW_GLOBAL = 1, + XML_CATA_ALLOW_DOCUMENT = 2, + XML_CATA_ALLOW_ALL = 3 +} xmlCatalogAllow; + +typedef struct _xmlCatalog xmlCatalog; +typedef xmlCatalog *xmlCatalogPtr; + +/* + * Operations on a given catalog. + */ +XMLPUBFUN xmlCatalogPtr XMLCALL + xmlNewCatalog (int sgml); +XMLPUBFUN xmlCatalogPtr XMLCALL + xmlLoadACatalog (const char *filename); +XMLPUBFUN xmlCatalogPtr XMLCALL + xmlLoadSGMLSuperCatalog (const char *filename); +XMLPUBFUN int XMLCALL + xmlConvertSGMLCatalog (xmlCatalogPtr catal); +XMLPUBFUN int XMLCALL + xmlACatalogAdd (xmlCatalogPtr catal, + const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +XMLPUBFUN int XMLCALL + xmlACatalogRemove (xmlCatalogPtr catal, + const xmlChar *value); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolve (xmlCatalogPtr catal, + const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolveSystem(xmlCatalogPtr catal, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolvePublic(xmlCatalogPtr catal, + const xmlChar *pubID); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolveURI (xmlCatalogPtr catal, + const xmlChar *URI); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlACatalogDump (xmlCatalogPtr catal, + FILE *out); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeCatalog (xmlCatalogPtr catal); +XMLPUBFUN int XMLCALL + xmlCatalogIsEmpty (xmlCatalogPtr catal); + +/* + * Global operations. + */ +XMLPUBFUN void XMLCALL + xmlInitializeCatalog (void); +XMLPUBFUN int XMLCALL + xmlLoadCatalog (const char *filename); +XMLPUBFUN void XMLCALL + xmlLoadCatalogs (const char *paths); +XMLPUBFUN void XMLCALL + xmlCatalogCleanup (void); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlCatalogDump (FILE *out); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolve (const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolveSystem (const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolvePublic (const xmlChar *pubID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolveURI (const xmlChar *URI); +XMLPUBFUN int XMLCALL + xmlCatalogAdd (const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +XMLPUBFUN int XMLCALL + xmlCatalogRemove (const xmlChar *value); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseCatalogFile (const char *filename); +XMLPUBFUN int XMLCALL + xmlCatalogConvert (void); + +/* + * Strictly minimal interfaces for per-document catalogs used + * by the parser. + */ +XMLPUBFUN void XMLCALL + xmlCatalogFreeLocal (void *catalogs); +XMLPUBFUN void * XMLCALL + xmlCatalogAddLocal (void *catalogs, + const xmlChar *URL); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogLocalResolve (void *catalogs, + const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogLocalResolveURI(void *catalogs, + const xmlChar *URI); +/* + * Preference settings. + */ +XMLPUBFUN int XMLCALL + xmlCatalogSetDebug (int level); +XMLPUBFUN xmlCatalogPrefer XMLCALL + xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer); +XMLPUBFUN void XMLCALL + xmlCatalogSetDefaults (xmlCatalogAllow allow); +XMLPUBFUN xmlCatalogAllow XMLCALL + xmlCatalogGetDefaults (void); + + +/* DEPRECATED interfaces */ +XMLPUBFUN const xmlChar * XMLCALL + xmlCatalogGetSystem (const xmlChar *sysID); +XMLPUBFUN const xmlChar * XMLCALL + xmlCatalogGetPublic (const xmlChar *pubID); + +#ifdef __cplusplus +} +#endif +#endif /* LIBXML_CATALOG_ENABLED */ +#endif /* __XML_CATALOG_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/chvalid.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/chvalid.h new file mode 100644 index 0000000..fb43016 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/chvalid.h @@ -0,0 +1,230 @@ +/* + * Summary: Unicode character range checking + * Description: this module exports interfaces for the character + * range validation APIs + * + * This file is automatically generated from the cvs source + * definition files using the genChRanges.py Python script + * + * Generation date: Mon Mar 27 11:09:48 2006 + * Sources: chvalid.def + * Author: William Brack + */ + +#ifndef __XML_CHVALID_H__ +#define __XML_CHVALID_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Define our typedefs and structures + * + */ +typedef struct _xmlChSRange xmlChSRange; +typedef xmlChSRange *xmlChSRangePtr; +struct _xmlChSRange { + unsigned short low; + unsigned short high; +}; + +typedef struct _xmlChLRange xmlChLRange; +typedef xmlChLRange *xmlChLRangePtr; +struct _xmlChLRange { + unsigned int low; + unsigned int high; +}; + +typedef struct _xmlChRangeGroup xmlChRangeGroup; +typedef xmlChRangeGroup *xmlChRangeGroupPtr; +struct _xmlChRangeGroup { + int nbShortRange; + int nbLongRange; + const xmlChSRange *shortRange; /* points to an array of ranges */ + const xmlChLRange *longRange; +}; + +/** + * Range checking routine + */ +XMLPUBFUN int XMLCALL + xmlCharInRange(unsigned int val, const xmlChRangeGroup *group); + + +/** + * xmlIsBaseChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBaseChar_ch(c) (((0x41 <= (c)) && ((c) <= 0x5a)) || \ + ((0x61 <= (c)) && ((c) <= 0x7a)) || \ + ((0xc0 <= (c)) && ((c) <= 0xd6)) || \ + ((0xd8 <= (c)) && ((c) <= 0xf6)) || \ + (0xf8 <= (c))) + +/** + * xmlIsBaseCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBaseCharQ(c) (((c) < 0x100) ? \ + xmlIsBaseChar_ch((c)) : \ + xmlCharInRange((c), &xmlIsBaseCharGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsBaseCharGroup; + +/** + * xmlIsBlank_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBlank_ch(c) (((c) == 0x20) || \ + ((0x9 <= (c)) && ((c) <= 0xa)) || \ + ((c) == 0xd)) + +/** + * xmlIsBlankQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBlankQ(c) (((c) < 0x100) ? \ + xmlIsBlank_ch((c)) : 0) + + +/** + * xmlIsChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsChar_ch(c) (((0x9 <= (c)) && ((c) <= 0xa)) || \ + ((c) == 0xd) || \ + (0x20 <= (c))) + +/** + * xmlIsCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsCharQ(c) (((c) < 0x100) ? \ + xmlIsChar_ch((c)) :\ + (((0x100 <= (c)) && ((c) <= 0xd7ff)) || \ + ((0xe000 <= (c)) && ((c) <= 0xfffd)) || \ + ((0x10000 <= (c)) && ((c) <= 0x10ffff)))) + +XMLPUBVAR const xmlChRangeGroup xmlIsCharGroup; + +/** + * xmlIsCombiningQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsCombiningQ(c) (((c) < 0x100) ? \ + 0 : \ + xmlCharInRange((c), &xmlIsCombiningGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsCombiningGroup; + +/** + * xmlIsDigit_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsDigit_ch(c) (((0x30 <= (c)) && ((c) <= 0x39))) + +/** + * xmlIsDigitQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsDigitQ(c) (((c) < 0x100) ? \ + xmlIsDigit_ch((c)) : \ + xmlCharInRange((c), &xmlIsDigitGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsDigitGroup; + +/** + * xmlIsExtender_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsExtender_ch(c) (((c) == 0xb7)) + +/** + * xmlIsExtenderQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsExtenderQ(c) (((c) < 0x100) ? \ + xmlIsExtender_ch((c)) : \ + xmlCharInRange((c), &xmlIsExtenderGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsExtenderGroup; + +/** + * xmlIsIdeographicQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsIdeographicQ(c) (((c) < 0x100) ? \ + 0 :\ + (((0x4e00 <= (c)) && ((c) <= 0x9fa5)) || \ + ((c) == 0x3007) || \ + ((0x3021 <= (c)) && ((c) <= 0x3029)))) + +XMLPUBVAR const xmlChRangeGroup xmlIsIdeographicGroup; +XMLPUBVAR const unsigned char xmlIsPubidChar_tab[256]; + +/** + * xmlIsPubidChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsPubidChar_ch(c) (xmlIsPubidChar_tab[(c)]) + +/** + * xmlIsPubidCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsPubidCharQ(c) (((c) < 0x100) ? \ + xmlIsPubidChar_ch((c)) : 0) + +XMLPUBFUN int XMLCALL + xmlIsBaseChar(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsBlank(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsChar(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsCombining(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsDigit(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsExtender(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsIdeographic(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsPubidChar(unsigned int ch); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_CHVALID_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/debugXML.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/debugXML.h new file mode 100644 index 0000000..5b3be13 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/debugXML.h @@ -0,0 +1,217 @@ +/* + * Summary: Tree debugging APIs + * Description: Interfaces to a set of routines used for debugging the tree + * produced by the XML parser. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __DEBUG_XML__ +#define __DEBUG_XML__ +#include +#include +#include + +#ifdef LIBXML_DEBUG_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The standard Dump routines. + */ +XMLPUBFUN void XMLCALL + xmlDebugDumpString (FILE *output, + const xmlChar *str); +XMLPUBFUN void XMLCALL + xmlDebugDumpAttr (FILE *output, + xmlAttrPtr attr, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpAttrList (FILE *output, + xmlAttrPtr attr, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpOneNode (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpNode (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpNodeList (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpDocumentHead(FILE *output, + xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlDebugDumpDocument (FILE *output, + xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlDebugDumpDTD (FILE *output, + xmlDtdPtr dtd); +XMLPUBFUN void XMLCALL + xmlDebugDumpEntities (FILE *output, + xmlDocPtr doc); + +/**************************************************************** + * * + * Checking routines * + * * + ****************************************************************/ + +XMLPUBFUN int XMLCALL + xmlDebugCheckDocument (FILE * output, + xmlDocPtr doc); + +/**************************************************************** + * * + * XML shell helpers * + * * + ****************************************************************/ + +XMLPUBFUN void XMLCALL + xmlLsOneNode (FILE *output, xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlLsCountNode (xmlNodePtr node); + +XMLPUBFUN const char * XMLCALL + xmlBoolToText (int boolval); + +/**************************************************************** + * * + * The XML shell related structures and functions * + * * + ****************************************************************/ + +#ifdef LIBXML_XPATH_ENABLED +/** + * xmlShellReadlineFunc: + * @prompt: a string prompt + * + * This is a generic signature for the XML shell input function. + * + * Returns a string which will be freed by the Shell. + */ +typedef char * (* xmlShellReadlineFunc)(char *prompt); + +/** + * xmlShellCtxt: + * + * A debugging shell context. + * TODO: add the defined function tables. + */ +typedef struct _xmlShellCtxt xmlShellCtxt; +typedef xmlShellCtxt *xmlShellCtxtPtr; +struct _xmlShellCtxt { + char *filename; + xmlDocPtr doc; + xmlNodePtr node; + xmlXPathContextPtr pctxt; + int loaded; + FILE *output; + xmlShellReadlineFunc input; +}; + +/** + * xmlShellCmd: + * @ctxt: a shell context + * @arg: a string argument + * @node: a first node + * @node2: a second node + * + * This is a generic signature for the XML shell functions. + * + * Returns an int, negative returns indicating errors. + */ +typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); + +XMLPUBFUN void XMLCALL + xmlShellPrintXPathError (int errorType, + const char *arg); +XMLPUBFUN void XMLCALL + xmlShellPrintXPathResult(xmlXPathObjectPtr list); +XMLPUBFUN int XMLCALL + xmlShellList (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellBase (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellDir (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellLoad (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlShellPrintNode (xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlShellCat (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellWrite (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellSave (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED +XMLPUBFUN int XMLCALL + xmlShellValidate (xmlShellCtxtPtr ctxt, + char *dtd, + xmlNodePtr node, + xmlNodePtr node2); +#endif /* LIBXML_VALID_ENABLED */ +XMLPUBFUN int XMLCALL + xmlShellDu (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr tree, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellPwd (xmlShellCtxtPtr ctxt, + char *buffer, + xmlNodePtr node, + xmlNodePtr node2); + +/* + * The Shell interface. + */ +XMLPUBFUN void XMLCALL + xmlShell (xmlDocPtr doc, + char *filename, + xmlShellReadlineFunc input, + FILE *output); + +#endif /* LIBXML_XPATH_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_DEBUG_ENABLED */ +#endif /* __DEBUG_XML__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/dict.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/dict.h new file mode 100644 index 0000000..b83db59 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/dict.h @@ -0,0 +1,86 @@ +/* + * Summary: string dictionary + * Description: dictionary of reusable strings, just used to avoid allocation + * and freeing operations. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_DICT_H__ +#define __XML_DICT_H__ + +#ifdef __cplusplus +#define __XML_EXTERNC extern "C" +#else +#define __XML_EXTERNC +#endif + +/* + * The dictionary. + */ +__XML_EXTERNC typedef struct _xmlDict xmlDict; +__XML_EXTERNC typedef xmlDict *xmlDictPtr; + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Initializer + */ +XMLPUBFUN int XMLCALL xmlInitializeDict(void); + +/* + * Constructor and destructor. + */ +XMLPUBFUN xmlDictPtr XMLCALL + xmlDictCreate (void); +XMLPUBFUN size_t XMLCALL + xmlDictSetLimit (xmlDictPtr dict, + size_t limit); +XMLPUBFUN size_t XMLCALL + xmlDictGetUsage (xmlDictPtr dict); +XMLPUBFUN xmlDictPtr XMLCALL + xmlDictCreateSub(xmlDictPtr sub); +XMLPUBFUN int XMLCALL + xmlDictReference(xmlDictPtr dict); +XMLPUBFUN void XMLCALL + xmlDictFree (xmlDictPtr dict); + +/* + * Lookup of entry in the dictionary. + */ +XMLPUBFUN const xmlChar * XMLCALL + xmlDictLookup (xmlDictPtr dict, + const xmlChar *name, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlDictExists (xmlDictPtr dict, + const xmlChar *name, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlDictQLookup (xmlDictPtr dict, + const xmlChar *prefix, + const xmlChar *name); +XMLPUBFUN int XMLCALL + xmlDictOwns (xmlDictPtr dict, + const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlDictSize (xmlDictPtr dict); + +/* + * Cleanup function + */ +XMLPUBFUN void XMLCALL + xmlDictCleanup (void); + +#ifdef __cplusplus +} +#endif +#endif /* ! __XML_DICT_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/encoding.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/encoding.h new file mode 100644 index 0000000..7967cc6 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/encoding.h @@ -0,0 +1,240 @@ +/* + * Summary: interface for the encoding conversion functions + * Description: interface for the encoding conversion functions needed for + * XML basic encoding and iconv() support. + * + * Related specs are + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_CHAR_ENCODING_H__ +#define __XML_CHAR_ENCODING_H__ + +#include + +#ifdef LIBXML_ICONV_ENABLED +#include +#endif +#ifdef LIBXML_ICU_ENABLED +#include +#endif +#ifdef __cplusplus +extern "C" { +#endif + +/* + * xmlCharEncoding: + * + * Predefined values for some standard encodings. + * Libxml does not do beforehand translation on UTF8 and ISOLatinX. + * It also supports ASCII, ISO-8859-1, and UTF16 (LE and BE) by default. + * + * Anything else would have to be translated to UTF8 before being + * given to the parser itself. The BOM for UTF16 and the encoding + * declaration are looked at and a converter is looked for at that + * point. If not found the parser stops here as asked by the XML REC. A + * converter can be registered by the user using xmlRegisterCharEncodingHandler + * but the current form doesn't allow stateful transcoding (a serious + * problem agreed !). If iconv has been found it will be used + * automatically and allow stateful transcoding, the simplest is then + * to be sure to enable iconv and to provide iconv libs for the encoding + * support needed. + * + * Note that the generic "UTF-16" is not a predefined value. Instead, only + * the specific UTF-16LE and UTF-16BE are present. + */ +typedef enum { + XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ + XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ + XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ + XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ + XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ + XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ + XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ + XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ + XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ + XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ + XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ + XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ + XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ + XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ + XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ + XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ + XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ + XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ + XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ + XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ + XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ + XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ +} xmlCharEncoding; + +/** + * xmlCharEncodingInputFunc: + * @out: a pointer to an array of bytes to store the UTF-8 result + * @outlen: the length of @out + * @in: a pointer to an array of chars in the original encoding + * @inlen: the length of @in + * + * Take a block of chars in the original encoding and try to convert + * it to an UTF-8 block of chars out. + * + * Returns the number of bytes written, -1 if lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of octets consumed. + */ +typedef int (* xmlCharEncodingInputFunc)(unsigned char *out, int *outlen, + const unsigned char *in, int *inlen); + + +/** + * xmlCharEncodingOutputFunc: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to another + * encoding. + * Note: a first call designed to produce heading info is called with + * in = NULL. If stateful this should also initialize the encoder state. + * + * Returns the number of bytes written, -1 if lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of octets produced. + */ +typedef int (* xmlCharEncodingOutputFunc)(unsigned char *out, int *outlen, + const unsigned char *in, int *inlen); + + +/* + * Block defining the handlers for non UTF-8 encodings. + * If iconv is supported, there are two extra fields. + */ +#ifdef LIBXML_ICU_ENABLED +struct _uconv_t { + UConverter *uconv; /* for conversion between an encoding and UTF-16 */ + UConverter *utf8; /* for conversion between UTF-8 and UTF-16 */ +}; +typedef struct _uconv_t uconv_t; +#endif + +typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; +typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; +struct _xmlCharEncodingHandler { + char *name; + xmlCharEncodingInputFunc input; + xmlCharEncodingOutputFunc output; +#ifdef LIBXML_ICONV_ENABLED + iconv_t iconv_in; + iconv_t iconv_out; +#endif /* LIBXML_ICONV_ENABLED */ +#ifdef LIBXML_ICU_ENABLED + uconv_t *uconv_in; + uconv_t *uconv_out; +#endif /* LIBXML_ICU_ENABLED */ +}; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces for encoding handlers. + */ +XMLPUBFUN void XMLCALL + xmlInitCharEncodingHandlers (void); +XMLPUBFUN void XMLCALL + xmlCleanupCharEncodingHandlers (void); +XMLPUBFUN void XMLCALL + xmlRegisterCharEncodingHandler (xmlCharEncodingHandlerPtr handler); +XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL + xmlGetCharEncodingHandler (xmlCharEncoding enc); +XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL + xmlFindCharEncodingHandler (const char *name); +XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL + xmlNewCharEncodingHandler (const char *name, + xmlCharEncodingInputFunc input, + xmlCharEncodingOutputFunc output); + +/* + * Interfaces for encoding names and aliases. + */ +XMLPUBFUN int XMLCALL + xmlAddEncodingAlias (const char *name, + const char *alias); +XMLPUBFUN int XMLCALL + xmlDelEncodingAlias (const char *alias); +XMLPUBFUN const char * XMLCALL + xmlGetEncodingAlias (const char *alias); +XMLPUBFUN void XMLCALL + xmlCleanupEncodingAliases (void); +XMLPUBFUN xmlCharEncoding XMLCALL + xmlParseCharEncoding (const char *name); +XMLPUBFUN const char * XMLCALL + xmlGetCharEncodingName (xmlCharEncoding enc); + +/* + * Interfaces directly used by the parsers. + */ +XMLPUBFUN xmlCharEncoding XMLCALL + xmlDetectCharEncoding (const unsigned char *in, + int len); + +XMLPUBFUN int XMLCALL + xmlCharEncOutFunc (xmlCharEncodingHandler *handler, + xmlBufferPtr out, + xmlBufferPtr in); + +XMLPUBFUN int XMLCALL + xmlCharEncInFunc (xmlCharEncodingHandler *handler, + xmlBufferPtr out, + xmlBufferPtr in); +XMLPUBFUN int XMLCALL + xmlCharEncFirstLine (xmlCharEncodingHandler *handler, + xmlBufferPtr out, + xmlBufferPtr in); +XMLPUBFUN int XMLCALL + xmlCharEncCloseFunc (xmlCharEncodingHandler *handler); + +/* + * Export a few useful functions + */ +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN int XMLCALL + UTF8Toisolat1 (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN int XMLCALL + isolat1ToUTF8 (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_CHAR_ENCODING_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/entities.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/entities.h new file mode 100644 index 0000000..47b4573 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/entities.h @@ -0,0 +1,151 @@ +/* + * Summary: interface for the XML entities handling + * Description: this module provides some of the entity API needed + * for the parser and applications. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_ENTITIES_H__ +#define __XML_ENTITIES_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The different valid entity types. + */ +typedef enum { + XML_INTERNAL_GENERAL_ENTITY = 1, + XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, + XML_INTERNAL_PARAMETER_ENTITY = 4, + XML_EXTERNAL_PARAMETER_ENTITY = 5, + XML_INTERNAL_PREDEFINED_ENTITY = 6 +} xmlEntityType; + +/* + * An unit of storage for an entity, contains the string, the value + * and the linkind data needed for the linking in the hash table. + */ + +struct _xmlEntity { + void *_private; /* application data */ + xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ + const xmlChar *name; /* Entity name */ + struct _xmlNode *children; /* First child link */ + struct _xmlNode *last; /* Last child link */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlChar *orig; /* content without ref substitution */ + xmlChar *content; /* content or ndata if unparsed */ + int length; /* the content length */ + xmlEntityType etype; /* The entity type */ + const xmlChar *ExternalID; /* External identifier for PUBLIC */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ + + struct _xmlEntity *nexte; /* unused */ + const xmlChar *URI; /* the full URI as computed */ + int owner; /* does the entity own the childrens */ + int checked; /* was the entity content checked */ + /* this is also used to count entities + * references done from that entity + * and if it contains '<' */ +}; + +/* + * All entities are stored in an hash table. + * There is 2 separate hash tables for global and parameter entities. + */ + +typedef struct _xmlHashTable xmlEntitiesTable; +typedef xmlEntitiesTable *xmlEntitiesTablePtr; + +/* + * External functions: + */ + +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN void XMLCALL + xmlInitializePredefinedEntities (void); +#endif /* LIBXML_LEGACY_ENABLED */ + +XMLPUBFUN xmlEntityPtr XMLCALL + xmlNewEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlAddDocEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlAddDtdEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetPredefinedEntity (const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetDocEntity (const xmlDoc *doc, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetDtdEntity (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetParameterEntity (xmlDocPtr doc, + const xmlChar *name); +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN const xmlChar * XMLCALL + xmlEncodeEntities (xmlDocPtr doc, + const xmlChar *input); +#endif /* LIBXML_LEGACY_ENABLED */ +XMLPUBFUN xmlChar * XMLCALL + xmlEncodeEntitiesReentrant(xmlDocPtr doc, + const xmlChar *input); +XMLPUBFUN xmlChar * XMLCALL + xmlEncodeSpecialChars (const xmlDoc *doc, + const xmlChar *input); +XMLPUBFUN xmlEntitiesTablePtr XMLCALL + xmlCreateEntitiesTable (void); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlEntitiesTablePtr XMLCALL + xmlCopyEntitiesTable (xmlEntitiesTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeEntitiesTable (xmlEntitiesTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpEntitiesTable (xmlBufferPtr buf, + xmlEntitiesTablePtr table); +XMLPUBFUN void XMLCALL + xmlDumpEntityDecl (xmlBufferPtr buf, + xmlEntityPtr ent); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN void XMLCALL + xmlCleanupPredefinedEntities(void); +#endif /* LIBXML_LEGACY_ENABLED */ + + +#ifdef __cplusplus +} +#endif + +# endif /* __XML_ENTITIES_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/globals.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/globals.h new file mode 100644 index 0000000..a9305aa --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/globals.h @@ -0,0 +1,509 @@ +/* + * Summary: interface for all global variables of the library + * Description: all the global variables and thread handling for + * those variables is handled by this module. + * + * The bottom of this file is automatically generated by build_glob.py + * based on the description file global.data + * + * Copy: See Copyright for the status of this software. + * + * Author: Gary Pennington , Daniel Veillard + */ + +#ifndef __XML_GLOBALS_H +#define __XML_GLOBALS_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void XMLCALL xmlInitGlobals(void); +XMLPUBFUN void XMLCALL xmlCleanupGlobals(void); + +/** + * xmlParserInputBufferCreateFilenameFunc: + * @URI: the URI to read from + * @enc: the requested source encoding + * + * Signature for the function doing the lookup for a suitable input method + * corresponding to an URI. + * + * Returns the new xmlParserInputBufferPtr in case of success or NULL if no + * method was found. + */ +typedef xmlParserInputBufferPtr (*xmlParserInputBufferCreateFilenameFunc) (const char *URI, + xmlCharEncoding enc); + + +/** + * xmlOutputBufferCreateFilenameFunc: + * @URI: the URI to write to + * @enc: the requested target encoding + * + * Signature for the function doing the lookup for a suitable output method + * corresponding to an URI. + * + * Returns the new xmlOutputBufferPtr in case of success or NULL if no + * method was found. + */ +typedef xmlOutputBufferPtr (*xmlOutputBufferCreateFilenameFunc) (const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc +XMLCALL xmlParserInputBufferCreateFilenameDefault (xmlParserInputBufferCreateFilenameFunc func); +XMLPUBFUN xmlOutputBufferCreateFilenameFunc +XMLCALL xmlOutputBufferCreateFilenameDefault (xmlOutputBufferCreateFilenameFunc func); + +/* + * Externally global symbols which need to be protected for backwards + * compatibility support. + */ + +#undef docbDefaultSAXHandler +#undef htmlDefaultSAXHandler +#undef oldXMLWDcompatibility +#undef xmlBufferAllocScheme +#undef xmlDefaultBufferSize +#undef xmlDefaultSAXHandler +#undef xmlDefaultSAXLocator +#undef xmlDoValidityCheckingDefaultValue +#undef xmlFree +#undef xmlGenericError +#undef xmlStructuredError +#undef xmlGenericErrorContext +#undef xmlStructuredErrorContext +#undef xmlGetWarningsDefaultValue +#undef xmlIndentTreeOutput +#undef xmlTreeIndentString +#undef xmlKeepBlanksDefaultValue +#undef xmlLineNumbersDefaultValue +#undef xmlLoadExtDtdDefaultValue +#undef xmlMalloc +#undef xmlMallocAtomic +#undef xmlMemStrdup +#undef xmlParserDebugEntities +#undef xmlParserVersion +#undef xmlPedanticParserDefaultValue +#undef xmlRealloc +#undef xmlSaveNoEmptyTags +#undef xmlSubstituteEntitiesDefaultValue +#undef xmlRegisterNodeDefaultValue +#undef xmlDeregisterNodeDefaultValue +#undef xmlLastError +#undef xmlParserInputBufferCreateFilenameValue +#undef xmlOutputBufferCreateFilenameValue + +/** + * xmlRegisterNodeFunc: + * @node: the current node + * + * Signature for the registration callback of a created node + */ +typedef void (*xmlRegisterNodeFunc) (xmlNodePtr node); +/** + * xmlDeregisterNodeFunc: + * @node: the current node + * + * Signature for the deregistration callback of a discarded node + */ +typedef void (*xmlDeregisterNodeFunc) (xmlNodePtr node); + +typedef struct _xmlGlobalState xmlGlobalState; +typedef xmlGlobalState *xmlGlobalStatePtr; +struct _xmlGlobalState +{ + const char *xmlParserVersion; + + xmlSAXLocator xmlDefaultSAXLocator; + xmlSAXHandlerV1 xmlDefaultSAXHandler; + xmlSAXHandlerV1 docbDefaultSAXHandler; + xmlSAXHandlerV1 htmlDefaultSAXHandler; + + xmlFreeFunc xmlFree; + xmlMallocFunc xmlMalloc; + xmlStrdupFunc xmlMemStrdup; + xmlReallocFunc xmlRealloc; + + xmlGenericErrorFunc xmlGenericError; + xmlStructuredErrorFunc xmlStructuredError; + void *xmlGenericErrorContext; + + int oldXMLWDcompatibility; + + xmlBufferAllocationScheme xmlBufferAllocScheme; + int xmlDefaultBufferSize; + + int xmlSubstituteEntitiesDefaultValue; + int xmlDoValidityCheckingDefaultValue; + int xmlGetWarningsDefaultValue; + int xmlKeepBlanksDefaultValue; + int xmlLineNumbersDefaultValue; + int xmlLoadExtDtdDefaultValue; + int xmlParserDebugEntities; + int xmlPedanticParserDefaultValue; + + int xmlSaveNoEmptyTags; + int xmlIndentTreeOutput; + const char *xmlTreeIndentString; + + xmlRegisterNodeFunc xmlRegisterNodeDefaultValue; + xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue; + + xmlMallocFunc xmlMallocAtomic; + xmlError xmlLastError; + + xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue; + xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue; + + void *xmlStructuredErrorContext; +}; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void XMLCALL xmlInitializeGlobalState(xmlGlobalStatePtr gs); + +XMLPUBFUN void XMLCALL xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler); + +XMLPUBFUN void XMLCALL xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler); + +XMLPUBFUN xmlRegisterNodeFunc XMLCALL xmlRegisterNodeDefault(xmlRegisterNodeFunc func); +XMLPUBFUN xmlRegisterNodeFunc XMLCALL xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func); +XMLPUBFUN xmlDeregisterNodeFunc XMLCALL xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func); +XMLPUBFUN xmlDeregisterNodeFunc XMLCALL xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func); + +XMLPUBFUN xmlOutputBufferCreateFilenameFunc XMLCALL + xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func); +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc XMLCALL + xmlThrDefParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func); + +/** DOC_DISABLE */ +/* + * In general the memory allocation entry points are not kept + * thread specific but this can be overridden by LIBXML_THREAD_ALLOC_ENABLED + * - xmlMalloc + * - xmlMallocAtomic + * - xmlRealloc + * - xmlMemStrdup + * - xmlFree + */ + +#ifdef LIBXML_THREAD_ALLOC_ENABLED +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlMallocFunc * XMLCALL __xmlMalloc(void); +#define xmlMalloc \ +(*(__xmlMalloc())) +#else +XMLPUBVAR xmlMallocFunc xmlMalloc; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlMallocFunc * XMLCALL __xmlMallocAtomic(void); +#define xmlMallocAtomic \ +(*(__xmlMallocAtomic())) +#else +XMLPUBVAR xmlMallocFunc xmlMallocAtomic; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlReallocFunc * XMLCALL __xmlRealloc(void); +#define xmlRealloc \ +(*(__xmlRealloc())) +#else +XMLPUBVAR xmlReallocFunc xmlRealloc; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlFreeFunc * XMLCALL __xmlFree(void); +#define xmlFree \ +(*(__xmlFree())) +#else +XMLPUBVAR xmlFreeFunc xmlFree; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlStrdupFunc * XMLCALL __xmlMemStrdup(void); +#define xmlMemStrdup \ +(*(__xmlMemStrdup())) +#else +XMLPUBVAR xmlStrdupFunc xmlMemStrdup; +#endif + +#else /* !LIBXML_THREAD_ALLOC_ENABLED */ +XMLPUBVAR xmlMallocFunc xmlMalloc; +XMLPUBVAR xmlMallocFunc xmlMallocAtomic; +XMLPUBVAR xmlReallocFunc xmlRealloc; +XMLPUBVAR xmlFreeFunc xmlFree; +XMLPUBVAR xmlStrdupFunc xmlMemStrdup; +#endif /* LIBXML_THREAD_ALLOC_ENABLED */ + +#ifdef LIBXML_DOCB_ENABLED +XMLPUBFUN xmlSAXHandlerV1 * XMLCALL __docbDefaultSAXHandler(void); +#ifdef LIBXML_THREAD_ENABLED +#define docbDefaultSAXHandler \ +(*(__docbDefaultSAXHandler())) +#else +XMLPUBVAR xmlSAXHandlerV1 docbDefaultSAXHandler; +#endif +#endif + +#ifdef LIBXML_HTML_ENABLED +XMLPUBFUN xmlSAXHandlerV1 * XMLCALL __htmlDefaultSAXHandler(void); +#ifdef LIBXML_THREAD_ENABLED +#define htmlDefaultSAXHandler \ +(*(__htmlDefaultSAXHandler())) +#else +XMLPUBVAR xmlSAXHandlerV1 htmlDefaultSAXHandler; +#endif +#endif + +XMLPUBFUN xmlError * XMLCALL __xmlLastError(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlLastError \ +(*(__xmlLastError())) +#else +XMLPUBVAR xmlError xmlLastError; +#endif + +/* + * Everything starting from the line below is + * Automatically generated by build_glob.py. + * Do not modify the previous line. + */ + + +XMLPUBFUN int * XMLCALL __oldXMLWDcompatibility(void); +#ifdef LIBXML_THREAD_ENABLED +#define oldXMLWDcompatibility \ +(*(__oldXMLWDcompatibility())) +#else +XMLPUBVAR int oldXMLWDcompatibility; +#endif + +XMLPUBFUN xmlBufferAllocationScheme * XMLCALL __xmlBufferAllocScheme(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlBufferAllocScheme \ +(*(__xmlBufferAllocScheme())) +#else +XMLPUBVAR xmlBufferAllocationScheme xmlBufferAllocScheme; +#endif +XMLPUBFUN xmlBufferAllocationScheme XMLCALL + xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v); + +XMLPUBFUN int * XMLCALL __xmlDefaultBufferSize(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDefaultBufferSize \ +(*(__xmlDefaultBufferSize())) +#else +XMLPUBVAR int xmlDefaultBufferSize; +#endif +XMLPUBFUN int XMLCALL xmlThrDefDefaultBufferSize(int v); + +XMLPUBFUN xmlSAXHandlerV1 * XMLCALL __xmlDefaultSAXHandler(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDefaultSAXHandler \ +(*(__xmlDefaultSAXHandler())) +#else +XMLPUBVAR xmlSAXHandlerV1 xmlDefaultSAXHandler; +#endif + +XMLPUBFUN xmlSAXLocator * XMLCALL __xmlDefaultSAXLocator(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDefaultSAXLocator \ +(*(__xmlDefaultSAXLocator())) +#else +XMLPUBVAR xmlSAXLocator xmlDefaultSAXLocator; +#endif + +XMLPUBFUN int * XMLCALL __xmlDoValidityCheckingDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDoValidityCheckingDefaultValue \ +(*(__xmlDoValidityCheckingDefaultValue())) +#else +XMLPUBVAR int xmlDoValidityCheckingDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefDoValidityCheckingDefaultValue(int v); + +XMLPUBFUN xmlGenericErrorFunc * XMLCALL __xmlGenericError(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlGenericError \ +(*(__xmlGenericError())) +#else +XMLPUBVAR xmlGenericErrorFunc xmlGenericError; +#endif + +XMLPUBFUN xmlStructuredErrorFunc * XMLCALL __xmlStructuredError(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlStructuredError \ +(*(__xmlStructuredError())) +#else +XMLPUBVAR xmlStructuredErrorFunc xmlStructuredError; +#endif + +XMLPUBFUN void * * XMLCALL __xmlGenericErrorContext(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlGenericErrorContext \ +(*(__xmlGenericErrorContext())) +#else +XMLPUBVAR void * xmlGenericErrorContext; +#endif + +XMLPUBFUN void * * XMLCALL __xmlStructuredErrorContext(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlStructuredErrorContext \ +(*(__xmlStructuredErrorContext())) +#else +XMLPUBVAR void * xmlStructuredErrorContext; +#endif + +XMLPUBFUN int * XMLCALL __xmlGetWarningsDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlGetWarningsDefaultValue \ +(*(__xmlGetWarningsDefaultValue())) +#else +XMLPUBVAR int xmlGetWarningsDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefGetWarningsDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlIndentTreeOutput(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlIndentTreeOutput \ +(*(__xmlIndentTreeOutput())) +#else +XMLPUBVAR int xmlIndentTreeOutput; +#endif +XMLPUBFUN int XMLCALL xmlThrDefIndentTreeOutput(int v); + +XMLPUBFUN const char * * XMLCALL __xmlTreeIndentString(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlTreeIndentString \ +(*(__xmlTreeIndentString())) +#else +XMLPUBVAR const char * xmlTreeIndentString; +#endif +XMLPUBFUN const char * XMLCALL xmlThrDefTreeIndentString(const char * v); + +XMLPUBFUN int * XMLCALL __xmlKeepBlanksDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlKeepBlanksDefaultValue \ +(*(__xmlKeepBlanksDefaultValue())) +#else +XMLPUBVAR int xmlKeepBlanksDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefKeepBlanksDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlLineNumbersDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlLineNumbersDefaultValue \ +(*(__xmlLineNumbersDefaultValue())) +#else +XMLPUBVAR int xmlLineNumbersDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefLineNumbersDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlLoadExtDtdDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlLoadExtDtdDefaultValue \ +(*(__xmlLoadExtDtdDefaultValue())) +#else +XMLPUBVAR int xmlLoadExtDtdDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefLoadExtDtdDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlParserDebugEntities(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlParserDebugEntities \ +(*(__xmlParserDebugEntities())) +#else +XMLPUBVAR int xmlParserDebugEntities; +#endif +XMLPUBFUN int XMLCALL xmlThrDefParserDebugEntities(int v); + +XMLPUBFUN const char * * XMLCALL __xmlParserVersion(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlParserVersion \ +(*(__xmlParserVersion())) +#else +XMLPUBVAR const char * xmlParserVersion; +#endif + +XMLPUBFUN int * XMLCALL __xmlPedanticParserDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlPedanticParserDefaultValue \ +(*(__xmlPedanticParserDefaultValue())) +#else +XMLPUBVAR int xmlPedanticParserDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefPedanticParserDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlSaveNoEmptyTags(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlSaveNoEmptyTags \ +(*(__xmlSaveNoEmptyTags())) +#else +XMLPUBVAR int xmlSaveNoEmptyTags; +#endif +XMLPUBFUN int XMLCALL xmlThrDefSaveNoEmptyTags(int v); + +XMLPUBFUN int * XMLCALL __xmlSubstituteEntitiesDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlSubstituteEntitiesDefaultValue \ +(*(__xmlSubstituteEntitiesDefaultValue())) +#else +XMLPUBVAR int xmlSubstituteEntitiesDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefSubstituteEntitiesDefaultValue(int v); + +XMLPUBFUN xmlRegisterNodeFunc * XMLCALL __xmlRegisterNodeDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlRegisterNodeDefaultValue \ +(*(__xmlRegisterNodeDefaultValue())) +#else +XMLPUBVAR xmlRegisterNodeFunc xmlRegisterNodeDefaultValue; +#endif + +XMLPUBFUN xmlDeregisterNodeFunc * XMLCALL __xmlDeregisterNodeDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDeregisterNodeDefaultValue \ +(*(__xmlDeregisterNodeDefaultValue())) +#else +XMLPUBVAR xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue; +#endif + +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc * XMLCALL \ + __xmlParserInputBufferCreateFilenameValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlParserInputBufferCreateFilenameValue \ +(*(__xmlParserInputBufferCreateFilenameValue())) +#else +XMLPUBVAR xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue; +#endif + +XMLPUBFUN xmlOutputBufferCreateFilenameFunc * XMLCALL __xmlOutputBufferCreateFilenameValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlOutputBufferCreateFilenameValue \ +(*(__xmlOutputBufferCreateFilenameValue())) +#else +XMLPUBVAR xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_GLOBALS_H */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/hash.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/hash.h new file mode 100644 index 0000000..dc8ab7e --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/hash.h @@ -0,0 +1,233 @@ +/* + * Summary: Chained hash tables + * Description: This module implements the hash table support used in + * various places in the library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Bjorn Reese + */ + +#ifndef __XML_HASH_H__ +#define __XML_HASH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The hash table. + */ +typedef struct _xmlHashTable xmlHashTable; +typedef xmlHashTable *xmlHashTablePtr; + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Recent version of gcc produce a warning when a function pointer is assigned + * to an object pointer, or vice versa. The following macro is a dirty hack + * to allow suppression of the warning. If your architecture has function + * pointers which are a different size than a void pointer, there may be some + * serious trouble within the library. + */ +/** + * XML_CAST_FPTR: + * @fptr: pointer to a function + * + * Macro to do a casting from an object pointer to a + * function pointer without encountering a warning from + * gcc + * + * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr)) + * This macro violated ISO C aliasing rules (gcc4 on s390 broke) + * so it is disabled now + */ + +#define XML_CAST_FPTR(fptr) fptr + + +/* + * function types: + */ +/** + * xmlHashDeallocator: + * @payload: the data in the hash + * @name: the name associated + * + * Callback to free data from a hash. + */ +typedef void (*xmlHashDeallocator)(void *payload, xmlChar *name); +/** + * xmlHashCopier: + * @payload: the data in the hash + * @name: the name associated + * + * Callback to copy data from a hash. + * + * Returns a copy of the data or NULL in case of error. + */ +typedef void *(*xmlHashCopier)(void *payload, xmlChar *name); +/** + * xmlHashScanner: + * @payload: the data in the hash + * @data: extra scannner data + * @name: the name associated + * + * Callback when scanning data in a hash with the simple scanner. + */ +typedef void (*xmlHashScanner)(void *payload, void *data, xmlChar *name); +/** + * xmlHashScannerFull: + * @payload: the data in the hash + * @data: extra scannner data + * @name: the name associated + * @name2: the second name associated + * @name3: the third name associated + * + * Callback when scanning data in a hash with the full scanner. + */ +typedef void (*xmlHashScannerFull)(void *payload, void *data, + const xmlChar *name, const xmlChar *name2, + const xmlChar *name3); + +/* + * Constructor and destructor. + */ +XMLPUBFUN xmlHashTablePtr XMLCALL + xmlHashCreate (int size); +XMLPUBFUN xmlHashTablePtr XMLCALL + xmlHashCreateDict(int size, + xmlDictPtr dict); +XMLPUBFUN void XMLCALL + xmlHashFree (xmlHashTablePtr table, + xmlHashDeallocator f); + +/* + * Add a new entry to the hash table. + */ +XMLPUBFUN int XMLCALL + xmlHashAddEntry (xmlHashTablePtr table, + const xmlChar *name, + void *userdata); +XMLPUBFUN int XMLCALL + xmlHashUpdateEntry(xmlHashTablePtr table, + const xmlChar *name, + void *userdata, + xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashAddEntry2(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + void *userdata); +XMLPUBFUN int XMLCALL + xmlHashUpdateEntry2(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + void *userdata, + xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashAddEntry3(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata); +XMLPUBFUN int XMLCALL + xmlHashUpdateEntry3(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata, + xmlHashDeallocator f); + +/* + * Remove an entry from the hash table. + */ +XMLPUBFUN int XMLCALL + xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, + xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + xmlHashDeallocator f); + +/* + * Retrieve the userdata. + */ +XMLPUBFUN void * XMLCALL + xmlHashLookup (xmlHashTablePtr table, + const xmlChar *name); +XMLPUBFUN void * XMLCALL + xmlHashLookup2 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2); +XMLPUBFUN void * XMLCALL + xmlHashLookup3 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3); +XMLPUBFUN void * XMLCALL + xmlHashQLookup (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN void * XMLCALL + xmlHashQLookup2 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *prefix, + const xmlChar *name2, + const xmlChar *prefix2); +XMLPUBFUN void * XMLCALL + xmlHashQLookup3 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *prefix, + const xmlChar *name2, + const xmlChar *prefix2, + const xmlChar *name3, + const xmlChar *prefix3); + +/* + * Helpers. + */ +XMLPUBFUN xmlHashTablePtr XMLCALL + xmlHashCopy (xmlHashTablePtr table, + xmlHashCopier f); +XMLPUBFUN int XMLCALL + xmlHashSize (xmlHashTablePtr table); +XMLPUBFUN void XMLCALL + xmlHashScan (xmlHashTablePtr table, + xmlHashScanner f, + void *data); +XMLPUBFUN void XMLCALL + xmlHashScan3 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashScanner f, + void *data); +XMLPUBFUN void XMLCALL + xmlHashScanFull (xmlHashTablePtr table, + xmlHashScannerFull f, + void *data); +XMLPUBFUN void XMLCALL + xmlHashScanFull3(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashScannerFull f, + void *data); +#ifdef __cplusplus +} +#endif +#endif /* ! __XML_HASH_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/list.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/list.h new file mode 100644 index 0000000..0504e0c --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/list.h @@ -0,0 +1,137 @@ +/* + * Summary: lists interfaces + * Description: this module implement the list support used in + * various place in the library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Gary Pennington + */ + +#ifndef __XML_LINK_INCLUDE__ +#define __XML_LINK_INCLUDE__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlLink xmlLink; +typedef xmlLink *xmlLinkPtr; + +typedef struct _xmlList xmlList; +typedef xmlList *xmlListPtr; + +/** + * xmlListDeallocator: + * @lk: the data to deallocate + * + * Callback function used to free data from a list. + */ +typedef void (*xmlListDeallocator) (xmlLinkPtr lk); +/** + * xmlListDataCompare: + * @data0: the first data + * @data1: the second data + * + * Callback function used to compare 2 data. + * + * Returns 0 is equality, -1 or 1 otherwise depending on the ordering. + */ +typedef int (*xmlListDataCompare) (const void *data0, const void *data1); +/** + * xmlListWalker: + * @data: the data found in the list + * @user: extra user provided data to the walker + * + * Callback function used when walking a list with xmlListWalk(). + * + * Returns 0 to stop walking the list, 1 otherwise. + */ +typedef int (*xmlListWalker) (const void *data, const void *user); + +/* Creation/Deletion */ +XMLPUBFUN xmlListPtr XMLCALL + xmlListCreate (xmlListDeallocator deallocator, + xmlListDataCompare compare); +XMLPUBFUN void XMLCALL + xmlListDelete (xmlListPtr l); + +/* Basic Operators */ +XMLPUBFUN void * XMLCALL + xmlListSearch (xmlListPtr l, + void *data); +XMLPUBFUN void * XMLCALL + xmlListReverseSearch (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListInsert (xmlListPtr l, + void *data) ; +XMLPUBFUN int XMLCALL + xmlListAppend (xmlListPtr l, + void *data) ; +XMLPUBFUN int XMLCALL + xmlListRemoveFirst (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListRemoveLast (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListRemoveAll (xmlListPtr l, + void *data); +XMLPUBFUN void XMLCALL + xmlListClear (xmlListPtr l); +XMLPUBFUN int XMLCALL + xmlListEmpty (xmlListPtr l); +XMLPUBFUN xmlLinkPtr XMLCALL + xmlListFront (xmlListPtr l); +XMLPUBFUN xmlLinkPtr XMLCALL + xmlListEnd (xmlListPtr l); +XMLPUBFUN int XMLCALL + xmlListSize (xmlListPtr l); + +XMLPUBFUN void XMLCALL + xmlListPopFront (xmlListPtr l); +XMLPUBFUN void XMLCALL + xmlListPopBack (xmlListPtr l); +XMLPUBFUN int XMLCALL + xmlListPushFront (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListPushBack (xmlListPtr l, + void *data); + +/* Advanced Operators */ +XMLPUBFUN void XMLCALL + xmlListReverse (xmlListPtr l); +XMLPUBFUN void XMLCALL + xmlListSort (xmlListPtr l); +XMLPUBFUN void XMLCALL + xmlListWalk (xmlListPtr l, + xmlListWalker walker, + const void *user); +XMLPUBFUN void XMLCALL + xmlListReverseWalk (xmlListPtr l, + xmlListWalker walker, + const void *user); +XMLPUBFUN void XMLCALL + xmlListMerge (xmlListPtr l1, + xmlListPtr l2); +XMLPUBFUN xmlListPtr XMLCALL + xmlListDup (const xmlListPtr old); +XMLPUBFUN int XMLCALL + xmlListCopy (xmlListPtr cur, + const xmlListPtr old); +/* Link operators */ +XMLPUBFUN void * XMLCALL + xmlLinkGetData (xmlLinkPtr lk); + +/* xmlListUnique() */ +/* xmlListSwap */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_LINK_INCLUDE__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/nanoftp.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/nanoftp.h new file mode 100644 index 0000000..abb4bf7 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/nanoftp.h @@ -0,0 +1,163 @@ +/* + * Summary: minimal FTP implementation + * Description: minimal FTP implementation allowing to fetch resources + * like external subset. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __NANO_FTP_H__ +#define __NANO_FTP_H__ + +#include + +#ifdef LIBXML_FTP_ENABLED + +/* Needed for portability to Windows 64 bits */ +#if defined(__MINGW32__) || defined(_WIN32_WCE) +#include +#else +/** + * SOCKET: + * + * macro used to provide portability of code to windows sockets + */ +#define SOCKET int +/** + * INVALID_SOCKET: + * + * macro used to provide portability of code to windows sockets + * the value to be used when the socket is not valid + */ +#undef INVALID_SOCKET +#define INVALID_SOCKET (-1) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * ftpListCallback: + * @userData: user provided data for the callback + * @filename: the file name (including "->" when links are shown) + * @attrib: the attribute string + * @owner: the owner string + * @group: the group string + * @size: the file size + * @links: the link count + * @year: the year + * @month: the month + * @day: the day + * @hour: the hour + * @minute: the minute + * + * A callback for the xmlNanoFTPList command. + * Note that only one of year and day:minute are specified. + */ +typedef void (*ftpListCallback) (void *userData, + const char *filename, const char *attrib, + const char *owner, const char *group, + unsigned long size, int links, int year, + const char *month, int day, int hour, + int minute); +/** + * ftpDataCallback: + * @userData: the user provided context + * @data: the data received + * @len: its size in bytes + * + * A callback for the xmlNanoFTPGet command. + */ +typedef void (*ftpDataCallback) (void *userData, + const char *data, + int len); + +/* + * Init + */ +XMLPUBFUN void XMLCALL + xmlNanoFTPInit (void); +XMLPUBFUN void XMLCALL + xmlNanoFTPCleanup (void); + +/* + * Creating/freeing contexts. + */ +XMLPUBFUN void * XMLCALL + xmlNanoFTPNewCtxt (const char *URL); +XMLPUBFUN void XMLCALL + xmlNanoFTPFreeCtxt (void * ctx); +XMLPUBFUN void * XMLCALL + xmlNanoFTPConnectTo (const char *server, + int port); +/* + * Opening/closing session connections. + */ +XMLPUBFUN void * XMLCALL + xmlNanoFTPOpen (const char *URL); +XMLPUBFUN int XMLCALL + xmlNanoFTPConnect (void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoFTPClose (void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoFTPQuit (void *ctx); +XMLPUBFUN void XMLCALL + xmlNanoFTPScanProxy (const char *URL); +XMLPUBFUN void XMLCALL + xmlNanoFTPProxy (const char *host, + int port, + const char *user, + const char *passwd, + int type); +XMLPUBFUN int XMLCALL + xmlNanoFTPUpdateURL (void *ctx, + const char *URL); + +/* + * Rather internal commands. + */ +XMLPUBFUN int XMLCALL + xmlNanoFTPGetResponse (void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoFTPCheckResponse (void *ctx); + +/* + * CD/DIR/GET handlers. + */ +XMLPUBFUN int XMLCALL + xmlNanoFTPCwd (void *ctx, + const char *directory); +XMLPUBFUN int XMLCALL + xmlNanoFTPDele (void *ctx, + const char *file); + +XMLPUBFUN SOCKET XMLCALL + xmlNanoFTPGetConnection (void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoFTPCloseConnection(void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoFTPList (void *ctx, + ftpListCallback callback, + void *userData, + const char *filename); +XMLPUBFUN SOCKET XMLCALL + xmlNanoFTPGetSocket (void *ctx, + const char *filename); +XMLPUBFUN int XMLCALL + xmlNanoFTPGet (void *ctx, + ftpDataCallback callback, + void *userData, + const char *filename); +XMLPUBFUN int XMLCALL + xmlNanoFTPRead (void *ctx, + void *dest, + int len); + +#ifdef __cplusplus +} +#endif +#endif /* LIBXML_FTP_ENABLED */ +#endif /* __NANO_FTP_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/nanohttp.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/nanohttp.h new file mode 100644 index 0000000..22b8fb4 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/nanohttp.h @@ -0,0 +1,81 @@ +/* + * Summary: minimal HTTP implementation + * Description: minimal HTTP implementation allowing to fetch resources + * like external subset. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __NANO_HTTP_H__ +#define __NANO_HTTP_H__ + +#include + +#ifdef LIBXML_HTTP_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN void XMLCALL + xmlNanoHTTPInit (void); +XMLPUBFUN void XMLCALL + xmlNanoHTTPCleanup (void); +XMLPUBFUN void XMLCALL + xmlNanoHTTPScanProxy (const char *URL); +XMLPUBFUN int XMLCALL + xmlNanoHTTPFetch (const char *URL, + const char *filename, + char **contentType); +XMLPUBFUN void * XMLCALL + xmlNanoHTTPMethod (const char *URL, + const char *method, + const char *input, + char **contentType, + const char *headers, + int ilen); +XMLPUBFUN void * XMLCALL + xmlNanoHTTPMethodRedir (const char *URL, + const char *method, + const char *input, + char **contentType, + char **redir, + const char *headers, + int ilen); +XMLPUBFUN void * XMLCALL + xmlNanoHTTPOpen (const char *URL, + char **contentType); +XMLPUBFUN void * XMLCALL + xmlNanoHTTPOpenRedir (const char *URL, + char **contentType, + char **redir); +XMLPUBFUN int XMLCALL + xmlNanoHTTPReturnCode (void *ctx); +XMLPUBFUN const char * XMLCALL + xmlNanoHTTPAuthHeader (void *ctx); +XMLPUBFUN const char * XMLCALL + xmlNanoHTTPRedir (void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoHTTPContentLength( void * ctx ); +XMLPUBFUN const char * XMLCALL + xmlNanoHTTPEncoding (void *ctx); +XMLPUBFUN const char * XMLCALL + xmlNanoHTTPMimeType (void *ctx); +XMLPUBFUN int XMLCALL + xmlNanoHTTPRead (void *ctx, + void *dest, + int len); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN int XMLCALL + xmlNanoHTTPSave (void *ctxt, + const char *filename); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN void XMLCALL + xmlNanoHTTPClose (void *ctx); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_HTTP_ENABLED */ +#endif /* __NANO_HTTP_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/parser.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/parser.h new file mode 100644 index 0000000..47fbec0 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/parser.h @@ -0,0 +1,1241 @@ +/* + * Summary: the core parser module + * Description: Interfaces, constants and types related to the XML parser + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PARSER_H__ +#define __XML_PARSER_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XML_DEFAULT_VERSION: + * + * The default version of XML used: 1.0 + */ +#define XML_DEFAULT_VERSION "1.0" + +/** + * xmlParserInput: + * + * An xmlParserInput is an input flow for the XML processor. + * Each entity parsed is associated an xmlParserInput (except the + * few predefined ones). This is the case both for internal entities + * - in which case the flow is already completely in memory - or + * external entities - in which case we use the buf structure for + * progressive reading and I18N conversions to the internal UTF-8 format. + */ + +/** + * xmlParserInputDeallocate: + * @str: the string to deallocate + * + * Callback for freeing some parser input allocations. + */ +typedef void (* xmlParserInputDeallocate)(xmlChar *str); + +struct _xmlParserInput { + /* Input buffer */ + xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ + + const char *filename; /* The file analyzed, if any */ + const char *directory; /* the directory/base of the file */ + const xmlChar *base; /* Base of the array to parse */ + const xmlChar *cur; /* Current char being parsed */ + const xmlChar *end; /* end of the array to parse */ + int length; /* length if known */ + int line; /* Current line */ + int col; /* Current column */ + /* + * NOTE: consumed is only tested for equality in the parser code, + * so even if there is an overflow this should not give troubles + * for parsing very large instances. + */ + unsigned long consumed; /* How many xmlChars already consumed */ + xmlParserInputDeallocate free; /* function to deallocate the base */ + const xmlChar *encoding; /* the encoding string for entity */ + const xmlChar *version; /* the version string for entity */ + int standalone; /* Was that entity marked standalone */ + int id; /* an unique identifier for the entity */ +}; + +/** + * xmlParserNodeInfo: + * + * The parser can be asked to collect Node informations, i.e. at what + * place in the file they were detected. + * NOTE: This is off by default and not very well tested. + */ +typedef struct _xmlParserNodeInfo xmlParserNodeInfo; +typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; + +struct _xmlParserNodeInfo { + const struct _xmlNode* node; + /* Position & line # that text that created the node begins & ends on */ + unsigned long begin_pos; + unsigned long begin_line; + unsigned long end_pos; + unsigned long end_line; +}; + +typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; +typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; +struct _xmlParserNodeInfoSeq { + unsigned long maximum; + unsigned long length; + xmlParserNodeInfo* buffer; +}; + +/** + * xmlParserInputState: + * + * The parser is now working also as a state based parser. + * The recursive one use the state info for entities processing. + */ +typedef enum { + XML_PARSER_EOF = -1, /* nothing is to be parsed */ + XML_PARSER_START = 0, /* nothing has been parsed */ + XML_PARSER_MISC, /* Misc* before int subset */ + XML_PARSER_PI, /* Within a processing instruction */ + XML_PARSER_DTD, /* within some DTD content */ + XML_PARSER_PROLOG, /* Misc* after internal subset */ + XML_PARSER_COMMENT, /* within a comment */ + XML_PARSER_START_TAG, /* within a start tag */ + XML_PARSER_CONTENT, /* within the content */ + XML_PARSER_CDATA_SECTION, /* within a CDATA section */ + XML_PARSER_END_TAG, /* within a closing tag */ + XML_PARSER_ENTITY_DECL, /* within an entity declaration */ + XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ + XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ + XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ + XML_PARSER_EPILOG, /* the Misc* after the last end tag */ + XML_PARSER_IGNORE, /* within an IGNORED section */ + XML_PARSER_PUBLIC_LITERAL /* within a PUBLIC value */ +} xmlParserInputState; + +/** + * XML_DETECT_IDS: + * + * Bit in the loadsubset context field to tell to do ID/REFs lookups. + * Use it to initialize xmlLoadExtDtdDefaultValue. + */ +#define XML_DETECT_IDS 2 + +/** + * XML_COMPLETE_ATTRS: + * + * Bit in the loadsubset context field to tell to do complete the + * elements attributes lists with the ones defaulted from the DTDs. + * Use it to initialize xmlLoadExtDtdDefaultValue. + */ +#define XML_COMPLETE_ATTRS 4 + +/** + * XML_SKIP_IDS: + * + * Bit in the loadsubset context field to tell to not do ID/REFs registration. + * Used to initialize xmlLoadExtDtdDefaultValue in some special cases. + */ +#define XML_SKIP_IDS 8 + +/** + * xmlParserMode: + * + * A parser can operate in various modes + */ +typedef enum { + XML_PARSE_UNKNOWN = 0, + XML_PARSE_DOM = 1, + XML_PARSE_SAX = 2, + XML_PARSE_PUSH_DOM = 3, + XML_PARSE_PUSH_SAX = 4, + XML_PARSE_READER = 5 +} xmlParserMode; + +/** + * xmlParserCtxt: + * + * The parser context. + * NOTE This doesn't completely define the parser state, the (current ?) + * design of the parser uses recursive function calls since this allow + * and easy mapping from the production rules of the specification + * to the actual code. The drawback is that the actual function call + * also reflect the parser state. However most of the parsing routines + * takes as the only argument the parser context pointer, so migrating + * to a state based parser for progressive parsing shouldn't be too hard. + */ +struct _xmlParserCtxt { + struct _xmlSAXHandler *sax; /* The SAX handler */ + void *userData; /* For SAX interface only, used by DOM build */ + xmlDocPtr myDoc; /* the document being built */ + int wellFormed; /* is the document well formed */ + int replaceEntities; /* shall we replace entities ? */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* the declared encoding, if any */ + int standalone; /* standalone document */ + int html; /* an HTML(1)/Docbook(2) document + * 3 is HTML after + * 10 is HTML after + */ + + /* Input stream stack */ + xmlParserInputPtr input; /* Current input stream */ + int inputNr; /* Number of current input streams */ + int inputMax; /* Max number of input streams */ + xmlParserInputPtr *inputTab; /* stack of inputs */ + + /* Node analysis stack only used for DOM building */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int record_info; /* Whether node info should be kept */ + xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ + + int errNo; /* error code */ + + int hasExternalSubset; /* reference and external subset */ + int hasPErefs; /* the internal subset has PE refs */ + int external; /* are we parsing an external entity */ + + int valid; /* is the document valid */ + int validate; /* shall we try to validate ? */ + xmlValidCtxt vctxt; /* The validity context */ + + xmlParserInputState instate; /* current type of input */ + int token; /* next char look-ahead */ + + char *directory; /* the data directory */ + + /* Node name stack */ + const xmlChar *name; /* Current parsed Node */ + int nameNr; /* Depth of the parsing stack */ + int nameMax; /* Max depth of the parsing stack */ + const xmlChar * *nameTab; /* array of nodes */ + + long nbChars; /* number of xmlChar processed */ + long checkIndex; /* used by progressive parsing lookup */ + int keepBlanks; /* ugly but ... */ + int disableSAX; /* SAX callbacks are disabled */ + int inSubset; /* Parsing is in int 1/ext 2 subset */ + const xmlChar * intSubName; /* name of subset */ + xmlChar * extSubURI; /* URI of external subset */ + xmlChar * extSubSystem; /* SYSTEM ID of external subset */ + + /* xml:space values */ + int * space; /* Should the parser preserve spaces */ + int spaceNr; /* Depth of the parsing stack */ + int spaceMax; /* Max depth of the parsing stack */ + int * spaceTab; /* array of space infos */ + + int depth; /* to prevent entity substitution loops */ + xmlParserInputPtr entity; /* used to check entities boundaries */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + int nodelen; /* Those two fields are there to */ + int nodemem; /* Speed up large node parsing */ + int pedantic; /* signal pedantic warnings */ + void *_private; /* For user data, libxml won't touch it */ + + int loadsubset; /* should the external subset be loaded */ + int linenumbers; /* set line number in element content */ + void *catalogs; /* document's own catalog */ + int recovery; /* run in recovery mode */ + int progressive; /* is this a progressive parsing */ + xmlDictPtr dict; /* dictionary for the parser */ + const xmlChar * *atts; /* array for the attributes callbacks */ + int maxatts; /* the size of the array */ + int docdict; /* use strings from dict to build tree */ + + /* + * pre-interned strings + */ + const xmlChar *str_xml; + const xmlChar *str_xmlns; + const xmlChar *str_xml_ns; + + /* + * Everything below is used only by the new SAX mode + */ + int sax2; /* operating in the new SAX mode */ + int nsNr; /* the number of inherited namespaces */ + int nsMax; /* the size of the arrays */ + const xmlChar * *nsTab; /* the array of prefix/namespace name */ + int *attallocs; /* which attribute were allocated */ + void * *pushTab; /* array of data for push */ + xmlHashTablePtr attsDefault; /* defaulted attributes if any */ + xmlHashTablePtr attsSpecial; /* non-CDATA attributes if any */ + int nsWellFormed; /* is the document XML Nanespace okay */ + int options; /* Extra options */ + + /* + * Those fields are needed only for treaming parsing so far + */ + int dictNames; /* Use dictionary names for the tree */ + int freeElemsNr; /* number of freed element nodes */ + xmlNodePtr freeElems; /* List of freed element nodes */ + int freeAttrsNr; /* number of freed attributes nodes */ + xmlAttrPtr freeAttrs; /* List of freed attributes nodes */ + + /* + * the complete error informations for the last error. + */ + xmlError lastError; + xmlParserMode parseMode; /* the parser mode */ + unsigned long nbentities; /* number of entities references */ + unsigned long sizeentities; /* size of parsed entities */ + + /* for use by HTML non-recursive parser */ + xmlParserNodeInfo *nodeInfo; /* Current NodeInfo */ + int nodeInfoNr; /* Depth of the parsing stack */ + int nodeInfoMax; /* Max depth of the parsing stack */ + xmlParserNodeInfo *nodeInfoTab; /* array of nodeInfos */ + + int input_id; /* we need to label inputs */ + unsigned long sizeentcopy; /* volume of entity copy */ +}; + +/** + * xmlSAXLocator: + * + * A SAX Locator. + */ +struct _xmlSAXLocator { + const xmlChar *(*getPublicId)(void *ctx); + const xmlChar *(*getSystemId)(void *ctx); + int (*getLineNumber)(void *ctx); + int (*getColumnNumber)(void *ctx); +}; + +/** + * xmlSAXHandler: + * + * A SAX handler is bunch of callbacks called by the parser when processing + * of the input generate data or structure informations. + */ + +/** + * resolveEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * Callback: + * The entity loader, to control the loading of external entities, + * the application can either: + * - override this resolveEntity() callback in the SAX block + * - or better use the xmlSetExternalEntityLoader() function to + * set up it's own entity resolution routine + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); +/** + * internalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on internal subset declaration. + */ +typedef void (*internalSubsetSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * externalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on external subset declaration. + */ +typedef void (*externalSubsetSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * getEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get an entity by name. + * + * Returns the xmlEntityPtr if found. + */ +typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, + const xmlChar *name); +/** + * getParameterEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get a parameter entity by name. + * + * Returns the xmlEntityPtr if found. + */ +typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, + const xmlChar *name); +/** + * entityDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the entity name + * @type: the entity type + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @content: the entity value (without processing). + * + * An entity definition has been parsed. + */ +typedef void (*entityDeclSAXFunc) (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +/** + * notationDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The name of the notation + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * What to do when a notation declaration has been parsed. + */ +typedef void (*notationDeclSAXFunc)(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +/** + * attributeDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @elem: the name of the element + * @fullname: the attribute name + * @type: the attribute type + * @def: the type of default value + * @defaultValue: the attribute default value + * @tree: the tree of enumerated value set + * + * An attribute definition has been parsed. + */ +typedef void (*attributeDeclSAXFunc)(void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +/** + * elementDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the element name + * @type: the element type + * @content: the element value tree + * + * An element definition has been parsed. + */ +typedef void (*elementDeclSAXFunc)(void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +/** + * unparsedEntityDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The name of the entity + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @notationName: the name of the notation + * + * What to do when an unparsed entity declaration is parsed. + */ +typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); +/** + * setDocumentLocatorSAXFunc: + * @ctx: the user data (XML parser context) + * @loc: A SAX Locator + * + * Receive the document locator at startup, actually xmlDefaultSAXLocator. + * Everything is available on the context, so this is useless in our case. + */ +typedef void (*setDocumentLocatorSAXFunc) (void *ctx, + xmlSAXLocatorPtr loc); +/** + * startDocumentSAXFunc: + * @ctx: the user data (XML parser context) + * + * Called when the document start being processed. + */ +typedef void (*startDocumentSAXFunc) (void *ctx); +/** + * endDocumentSAXFunc: + * @ctx: the user data (XML parser context) + * + * Called when the document end has been detected. + */ +typedef void (*endDocumentSAXFunc) (void *ctx); +/** + * startElementSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The element name, including namespace prefix + * @atts: An array of name/value attributes pairs, NULL terminated + * + * Called when an opening tag has been processed. + */ +typedef void (*startElementSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar **atts); +/** + * endElementSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The element name + * + * Called when the end of an element has been detected. + */ +typedef void (*endElementSAXFunc) (void *ctx, + const xmlChar *name); +/** + * attributeSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The attribute name, including namespace prefix + * @value: The attribute value + * + * Handle an attribute that has been read by the parser. + * The default handling is to convert the attribute into an + * DOM subtree and past it in a new xmlAttr element added to + * the element. + */ +typedef void (*attributeSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *value); +/** + * referenceSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Called when an entity reference is detected. + */ +typedef void (*referenceSAXFunc) (void *ctx, + const xmlChar *name); +/** + * charactersSAXFunc: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * Receiving some chars from the parser. + */ +typedef void (*charactersSAXFunc) (void *ctx, + const xmlChar *ch, + int len); +/** + * ignorableWhitespaceSAXFunc: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * Receiving some ignorable whitespaces from the parser. + * UNUSED: by default the DOM building will use characters. + */ +typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, + const xmlChar *ch, + int len); +/** + * processingInstructionSAXFunc: + * @ctx: the user data (XML parser context) + * @target: the target name + * @data: the PI data's + * + * A processing instruction has been parsed. + */ +typedef void (*processingInstructionSAXFunc) (void *ctx, + const xmlChar *target, + const xmlChar *data); +/** + * commentSAXFunc: + * @ctx: the user data (XML parser context) + * @value: the comment content + * + * A comment has been parsed. + */ +typedef void (*commentSAXFunc) (void *ctx, + const xmlChar *value); +/** + * cdataBlockSAXFunc: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * Called when a pcdata block has been parsed. + */ +typedef void (*cdataBlockSAXFunc) ( + void *ctx, + const xmlChar *value, + int len); +/** + * warningSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a warning messages, callback. + */ +typedef void (XMLCDECL *warningSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * errorSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format an error messages, callback. + */ +typedef void (XMLCDECL *errorSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * fatalErrorSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format fatal error messages, callback. + * Note: so far fatalError() SAX callbacks are not used, error() + * get all the callbacks for errors. + */ +typedef void (XMLCDECL *fatalErrorSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * isStandaloneSAXFunc: + * @ctx: the user data (XML parser context) + * + * Is this document tagged standalone? + * + * Returns 1 if true + */ +typedef int (*isStandaloneSAXFunc) (void *ctx); +/** + * hasInternalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * + * Does this document has an internal subset. + * + * Returns 1 if true + */ +typedef int (*hasInternalSubsetSAXFunc) (void *ctx); + +/** + * hasExternalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * + * Does this document has an external subset? + * + * Returns 1 if true + */ +typedef int (*hasExternalSubsetSAXFunc) (void *ctx); + +/************************************************************************ + * * + * The SAX version 2 API extensions * + * * + ************************************************************************/ +/** + * XML_SAX2_MAGIC: + * + * Special constant found in SAX2 blocks initialized fields + */ +#define XML_SAX2_MAGIC 0xDEEDBEAF + +/** + * startElementNsSAX2Func: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @nb_namespaces: number of namespace definitions on that node + * @namespaces: pointer to the array of prefix/URI pairs namespace definitions + * @nb_attributes: the number of attributes on that node + * @nb_defaulted: the number of defaulted attributes. The defaulted + * ones are at the end of the array + * @attributes: pointer to the array of (localname/prefix/URI/value/end) + * attribute values. + * + * SAX2 callback when an element start has been detected by the parser. + * It provides the namespace informations for the element, as well as + * the new namespace declarations on the element. + */ + +typedef void (*startElementNsSAX2Func) (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes); + +/** + * endElementNsSAX2Func: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * + * SAX2 callback when an element end has been detected by the parser. + * It provides the namespace informations for the element. + */ + +typedef void (*endElementNsSAX2Func) (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI); + + +struct _xmlSAXHandler { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; /* unused error() get all the errors */ + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; + unsigned int initialized; + /* The following fields are extensions available only on version 2 */ + void *_private; + startElementNsSAX2Func startElementNs; + endElementNsSAX2Func endElementNs; + xmlStructuredErrorFunc serror; +}; + +/* + * SAX Version 1 + */ +typedef struct _xmlSAXHandlerV1 xmlSAXHandlerV1; +typedef xmlSAXHandlerV1 *xmlSAXHandlerV1Ptr; +struct _xmlSAXHandlerV1 { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; /* unused error() get all the errors */ + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; + unsigned int initialized; +}; + + +/** + * xmlExternalEntityLoader: + * @URL: The System ID of the resource requested + * @ID: The Public ID of the resource requested + * @context: the XML parser context + * + * External entity loaders types. + * + * Returns the entity input parser. + */ +typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL, + const char *ID, + xmlParserCtxtPtr context); + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Init/Cleanup + */ +XMLPUBFUN void XMLCALL + xmlInitParser (void); +XMLPUBFUN void XMLCALL + xmlCleanupParser (void); + +/* + * Input functions + */ +XMLPUBFUN int XMLCALL + xmlParserInputRead (xmlParserInputPtr in, + int len); +XMLPUBFUN int XMLCALL + xmlParserInputGrow (xmlParserInputPtr in, + int len); + +/* + * Basic parsing Interfaces + */ +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseDoc (const xmlChar *cur); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseFile (const char *filename); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseMemory (const char *buffer, + int size); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN int XMLCALL + xmlSubstituteEntitiesDefault(int val); +XMLPUBFUN int XMLCALL + xmlKeepBlanksDefault (int val); +XMLPUBFUN void XMLCALL + xmlStopParser (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlPedanticParserDefault(int val); +XMLPUBFUN int XMLCALL + xmlLineNumbersDefault (int val); + +#ifdef LIBXML_SAX1_ENABLED +/* + * Recovery mode + */ +XMLPUBFUN xmlDocPtr XMLCALL + xmlRecoverDoc (const xmlChar *cur); +XMLPUBFUN xmlDocPtr XMLCALL + xmlRecoverMemory (const char *buffer, + int size); +XMLPUBFUN xmlDocPtr XMLCALL + xmlRecoverFile (const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ + +/* + * Less common routines and SAX interfaces + */ +XMLPUBFUN int XMLCALL + xmlParseDocument (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseExtParsedEnt (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlSAXUserParseFile (xmlSAXHandlerPtr sax, + void *user_data, + const char *filename); +XMLPUBFUN int XMLCALL + xmlSAXUserParseMemory (xmlSAXHandlerPtr sax, + void *user_data, + const char *buffer, + int size); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseDoc (xmlSAXHandlerPtr sax, + const xmlChar *cur, + int recovery); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseMemory (xmlSAXHandlerPtr sax, + const char *buffer, + int size, + int recovery); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseMemoryWithData (xmlSAXHandlerPtr sax, + const char *buffer, + int size, + int recovery, + void *data); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseFile (xmlSAXHandlerPtr sax, + const char *filename, + int recovery); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseFileWithData (xmlSAXHandlerPtr sax, + const char *filename, + int recovery, + void *data); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseEntity (xmlSAXHandlerPtr sax, + const char *filename); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseEntity (const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +XMLPUBFUN xmlDtdPtr XMLCALL + xmlSAXParseDTD (xmlSAXHandlerPtr sax, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlParseDTD (const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlIOParseDTD (xmlSAXHandlerPtr sax, + xmlParserInputBufferPtr input, + xmlCharEncoding enc); +#endif /* LIBXML_VALID_ENABLE */ +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlParseBalancedChunkMemory(xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *string, + xmlNodePtr *lst); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN xmlParserErrors XMLCALL + xmlParseInNodeContext (xmlNodePtr node, + const char *data, + int datalen, + int options, + xmlNodePtr *lst); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *string, + xmlNodePtr *lst, + int recover); +XMLPUBFUN int XMLCALL + xmlParseExternalEntity (xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *URL, + const xmlChar *ID, + xmlNodePtr *lst); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN int XMLCALL + xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, + const xmlChar *URL, + const xmlChar *ID, + xmlNodePtr *lst); + +/* + * Parser contexts handling. + */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlNewParserCtxt (void); +XMLPUBFUN int XMLCALL + xmlInitParserCtxt (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlClearParserCtxt (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlFreeParserCtxt (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN void XMLCALL + xmlSetupParserForBuffer (xmlParserCtxtPtr ctxt, + const xmlChar* buffer, + const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateDocParserCtxt (const xmlChar *cur); + +#ifdef LIBXML_LEGACY_ENABLED +/* + * Reading/setting optional parsing features. + */ +XMLPUBFUN int XMLCALL + xmlGetFeaturesList (int *len, + const char **result); +XMLPUBFUN int XMLCALL + xmlGetFeature (xmlParserCtxtPtr ctxt, + const char *name, + void *result); +XMLPUBFUN int XMLCALL + xmlSetFeature (xmlParserCtxtPtr ctxt, + const char *name, + void *value); +#endif /* LIBXML_LEGACY_ENABLED */ + +#ifdef LIBXML_PUSH_ENABLED +/* + * Interfaces for the Push mode. + */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename); +XMLPUBFUN int XMLCALL + xmlParseChunk (xmlParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +#endif /* LIBXML_PUSH_ENABLED */ + +/* + * Special I/O mode. + */ + +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateIOParserCtxt (xmlSAXHandlerPtr sax, + void *user_data, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + xmlCharEncoding enc); + +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewIOInputStream (xmlParserCtxtPtr ctxt, + xmlParserInputBufferPtr input, + xmlCharEncoding enc); + +/* + * Node infos. + */ +XMLPUBFUN const xmlParserNodeInfo* XMLCALL + xmlParserFindNodeInfo (const xmlParserCtxtPtr ctxt, + const xmlNodePtr node); +XMLPUBFUN void XMLCALL + xmlInitNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); +XMLPUBFUN void XMLCALL + xmlClearNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); +XMLPUBFUN unsigned long XMLCALL + xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, + const xmlNodePtr node); +XMLPUBFUN void XMLCALL + xmlParserAddNodeInfo (xmlParserCtxtPtr ctxt, + const xmlParserNodeInfoPtr info); + +/* + * External entities handling actually implemented in xmlIO. + */ + +XMLPUBFUN void XMLCALL + xmlSetExternalEntityLoader(xmlExternalEntityLoader f); +XMLPUBFUN xmlExternalEntityLoader XMLCALL + xmlGetExternalEntityLoader(void); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlLoadExternalEntity (const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + +/* + * Index lookup, actually implemented in the encoding module + */ +XMLPUBFUN long XMLCALL + xmlByteConsumed (xmlParserCtxtPtr ctxt); + +/* + * New set of simpler/more flexible APIs + */ +/** + * xmlParserOption: + * + * This is the set of XML parser options that can be passed down + * to the xmlReadDoc() and similar calls. + */ +typedef enum { + XML_PARSE_RECOVER = 1<<0, /* recover on errors */ + XML_PARSE_NOENT = 1<<1, /* substitute entities */ + XML_PARSE_DTDLOAD = 1<<2, /* load the external subset */ + XML_PARSE_DTDATTR = 1<<3, /* default DTD attributes */ + XML_PARSE_DTDVALID = 1<<4, /* validate with the DTD */ + XML_PARSE_NOERROR = 1<<5, /* suppress error reports */ + XML_PARSE_NOWARNING = 1<<6, /* suppress warning reports */ + XML_PARSE_PEDANTIC = 1<<7, /* pedantic error reporting */ + XML_PARSE_NOBLANKS = 1<<8, /* remove blank nodes */ + XML_PARSE_SAX1 = 1<<9, /* use the SAX1 interface internally */ + XML_PARSE_XINCLUDE = 1<<10,/* Implement XInclude substitition */ + XML_PARSE_NONET = 1<<11,/* Forbid network access */ + XML_PARSE_NODICT = 1<<12,/* Do not reuse the context dictionary */ + XML_PARSE_NSCLEAN = 1<<13,/* remove redundant namespaces declarations */ + XML_PARSE_NOCDATA = 1<<14,/* merge CDATA as text nodes */ + XML_PARSE_NOXINCNODE= 1<<15,/* do not generate XINCLUDE START/END nodes */ + XML_PARSE_COMPACT = 1<<16,/* compact small text nodes; no modification of + the tree allowed afterwards (will possibly + crash if you try to modify the tree) */ + XML_PARSE_OLD10 = 1<<17,/* parse using XML-1.0 before update 5 */ + XML_PARSE_NOBASEFIX = 1<<18,/* do not fixup XINCLUDE xml:base uris */ + XML_PARSE_HUGE = 1<<19,/* relax any hardcoded limit from the parser */ + XML_PARSE_OLDSAX = 1<<20,/* parse using SAX2 interface before 2.7.0 */ + XML_PARSE_IGNORE_ENC= 1<<21,/* ignore internal document encoding hint */ + XML_PARSE_BIG_LINES = 1<<22 /* Store big lines numbers in text PSVI field */ +} xmlParserOption; + +XMLPUBFUN void XMLCALL + xmlCtxtReset (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlCtxtResetPush (xmlParserCtxtPtr ctxt, + const char *chunk, + int size, + const char *filename, + const char *encoding); +XMLPUBFUN int XMLCALL + xmlCtxtUseOptions (xmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadDoc (const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadFile (const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadDoc (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadFile (xmlParserCtxtPtr ctxt, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadMemory (xmlParserCtxtPtr ctxt, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadFd (xmlParserCtxtPtr ctxt, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadIO (xmlParserCtxtPtr ctxt, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +/* + * Library wide options + */ +/** + * xmlFeature: + * + * Used to examine the existance of features that can be enabled + * or disabled at compile-time. + * They used to be called XML_FEATURE_xxx but this clashed with Expat + */ +typedef enum { + XML_WITH_THREAD = 1, + XML_WITH_TREE = 2, + XML_WITH_OUTPUT = 3, + XML_WITH_PUSH = 4, + XML_WITH_READER = 5, + XML_WITH_PATTERN = 6, + XML_WITH_WRITER = 7, + XML_WITH_SAX1 = 8, + XML_WITH_FTP = 9, + XML_WITH_HTTP = 10, + XML_WITH_VALID = 11, + XML_WITH_HTML = 12, + XML_WITH_LEGACY = 13, + XML_WITH_C14N = 14, + XML_WITH_CATALOG = 15, + XML_WITH_XPATH = 16, + XML_WITH_XPTR = 17, + XML_WITH_XINCLUDE = 18, + XML_WITH_ICONV = 19, + XML_WITH_ISO8859X = 20, + XML_WITH_UNICODE = 21, + XML_WITH_REGEXP = 22, + XML_WITH_AUTOMATA = 23, + XML_WITH_EXPR = 24, + XML_WITH_SCHEMAS = 25, + XML_WITH_SCHEMATRON = 26, + XML_WITH_MODULES = 27, + XML_WITH_DEBUG = 28, + XML_WITH_DEBUG_MEM = 29, + XML_WITH_DEBUG_RUN = 30, + XML_WITH_ZLIB = 31, + XML_WITH_ICU = 32, + XML_WITH_LZMA = 33, + XML_WITH_NONE = 99999 /* just to be sure of allocation size */ +} xmlFeature; + +XMLPUBFUN int XMLCALL + xmlHasFeature (xmlFeature feature); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_PARSER_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/parserInternals.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/parserInternals.h new file mode 100644 index 0000000..6065320 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/parserInternals.h @@ -0,0 +1,644 @@ +/* + * Summary: internals routines and limits exported by the parser. + * Description: this module exports a number of internal parsing routines + * they are not really all intended for applications but + * can prove useful doing low level processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PARSER_INTERNALS_H__ +#define __XML_PARSER_INTERNALS_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlParserMaxDepth: + * + * arbitrary depth limit for the XML documents that we allow to + * process. This is not a limitation of the parser but a safety + * boundary feature, use XML_PARSE_HUGE option to override it. + */ +XMLPUBVAR unsigned int xmlParserMaxDepth; + +/** + * XML_MAX_TEXT_LENGTH: + * + * Maximum size allowed for a single text node when building a tree. + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + * Introduced in 2.9.0 + */ +#define XML_MAX_TEXT_LENGTH 10000000 + +/** + * XML_MAX_NAME_LENGTH: + * + * Maximum size allowed for a markup identitier + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + * Note that with the use of parsing dictionaries overriding the limit + * may result in more runtime memory usage in face of "unfriendly' content + * Introduced in 2.9.0 + */ +#define XML_MAX_NAME_LENGTH 50000 + +/** + * XML_MAX_DICTIONARY_LIMIT: + * + * Maximum size allowed by the parser for a dictionary by default + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + * Introduced in 2.9.0 + */ +#define XML_MAX_DICTIONARY_LIMIT 10000000 + +/** + * XML_MAX_LOOKUP_LIMIT: + * + * Maximum size allowed by the parser for ahead lookup + * This is an upper boundary enforced by the parser to avoid bad + * behaviour on "unfriendly' content + * Introduced in 2.9.0 + */ +#define XML_MAX_LOOKUP_LIMIT 10000000 + +/** + * XML_MAX_NAMELEN: + * + * Identifiers can be longer, but this will be more costly + * at runtime. + */ +#define XML_MAX_NAMELEN 100 + +/** + * INPUT_CHUNK: + * + * The parser tries to always have that amount of input ready. + * One of the point is providing context when reporting errors. + */ +#define INPUT_CHUNK 250 + +/************************************************************************ + * * + * UNICODE version of the macros. * + * * + ************************************************************************/ +/** + * IS_BYTE_CHAR: + * @c: an byte value (int) + * + * Macro to check the following production in the XML spec: + * + * [2] Char ::= #x9 | #xA | #xD | [#x20...] + * any byte character in the accepted range + */ +#define IS_BYTE_CHAR(c) xmlIsChar_ch(c) + +/** + * IS_CHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] + * | [#x10000-#x10FFFF] + * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. + */ +#define IS_CHAR(c) xmlIsCharQ(c) + +/** + * IS_CHAR_CH: + * @c: an xmlChar (usually an unsigned char) + * + * Behaves like IS_CHAR on single-byte value + */ +#define IS_CHAR_CH(c) xmlIsChar_ch(c) + +/** + * IS_BLANK: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [3] S ::= (#x20 | #x9 | #xD | #xA)+ + */ +#define IS_BLANK(c) xmlIsBlankQ(c) + +/** + * IS_BLANK_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Behaviour same as IS_BLANK + */ +#define IS_BLANK_CH(c) xmlIsBlank_ch(c) + +/** + * IS_BASECHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [85] BaseChar ::= ... long list see REC ... + */ +#define IS_BASECHAR(c) xmlIsBaseCharQ(c) + +/** + * IS_DIGIT: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [88] Digit ::= ... long list see REC ... + */ +#define IS_DIGIT(c) xmlIsDigitQ(c) + +/** + * IS_DIGIT_CH: + * @c: an xmlChar value (usually an unsigned char) + * + * Behaves like IS_DIGIT but with a single byte argument + */ +#define IS_DIGIT_CH(c) xmlIsDigit_ch(c) + +/** + * IS_COMBINING: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [87] CombiningChar ::= ... long list see REC ... + */ +#define IS_COMBINING(c) xmlIsCombiningQ(c) + +/** + * IS_COMBINING_CH: + * @c: an xmlChar (usually an unsigned char) + * + * Always false (all combining chars > 0xff) + */ +#define IS_COMBINING_CH(c) 0 + +/** + * IS_EXTENDER: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | + * #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] | + * [#x309D-#x309E] | [#x30FC-#x30FE] + */ +#define IS_EXTENDER(c) xmlIsExtenderQ(c) + +/** + * IS_EXTENDER_CH: + * @c: an xmlChar value (usually an unsigned char) + * + * Behaves like IS_EXTENDER but with a single-byte argument + */ +#define IS_EXTENDER_CH(c) xmlIsExtender_ch(c) + +/** + * IS_IDEOGRAPHIC: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029] + */ +#define IS_IDEOGRAPHIC(c) xmlIsIdeographicQ(c) + +/** + * IS_LETTER: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [84] Letter ::= BaseChar | Ideographic + */ +#define IS_LETTER(c) (IS_BASECHAR(c) || IS_IDEOGRAPHIC(c)) + +/** + * IS_LETTER_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Macro behaves like IS_LETTER, but only check base chars + * + */ +#define IS_LETTER_CH(c) xmlIsBaseChar_ch(c) + +/** + * IS_ASCII_LETTER: + * @c: an xmlChar value + * + * Macro to check [a-zA-Z] + * + */ +#define IS_ASCII_LETTER(c) (((0x41 <= (c)) && ((c) <= 0x5a)) || \ + ((0x61 <= (c)) && ((c) <= 0x7a))) + +/** + * IS_ASCII_DIGIT: + * @c: an xmlChar value + * + * Macro to check [0-9] + * + */ +#define IS_ASCII_DIGIT(c) ((0x30 <= (c)) && ((c) <= 0x39)) + +/** + * IS_PUBIDCHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + */ +#define IS_PUBIDCHAR(c) xmlIsPubidCharQ(c) + +/** + * IS_PUBIDCHAR_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Same as IS_PUBIDCHAR but for single-byte value + */ +#define IS_PUBIDCHAR_CH(c) xmlIsPubidChar_ch(c) + +/** + * SKIP_EOL: + * @p: and UTF8 string pointer + * + * Skips the end of line chars. + */ +#define SKIP_EOL(p) \ + if (*(p) == 0x13) { p++ ; if (*(p) == 0x10) p++; } \ + if (*(p) == 0x10) { p++ ; if (*(p) == 0x13) p++; } + +/** + * MOVETO_ENDTAG: + * @p: and UTF8 string pointer + * + * Skips to the next '>' char. + */ +#define MOVETO_ENDTAG(p) \ + while ((*p) && (*(p) != '>')) (p)++ + +/** + * MOVETO_STARTTAG: + * @p: and UTF8 string pointer + * + * Skips to the next '<' char. + */ +#define MOVETO_STARTTAG(p) \ + while ((*p) && (*(p) != '<')) (p)++ + +/** + * Global variables used for predefined strings. + */ +XMLPUBVAR const xmlChar xmlStringText[]; +XMLPUBVAR const xmlChar xmlStringTextNoenc[]; +XMLPUBVAR const xmlChar xmlStringComment[]; + +/* + * Function to finish the work of the macros where needed. + */ +XMLPUBFUN int XMLCALL xmlIsLetter (int c); + +/** + * Parser context. + */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateFileParserCtxt (const char *filename); +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateURLParserCtxt (const char *filename, + int options); +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateMemoryParserCtxt(const char *buffer, + int size); +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateEntityParserCtxt(const xmlChar *URL, + const xmlChar *ID, + const xmlChar *base); +XMLPUBFUN int XMLCALL + xmlSwitchEncoding (xmlParserCtxtPtr ctxt, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + xmlSwitchToEncoding (xmlParserCtxtPtr ctxt, + xmlCharEncodingHandlerPtr handler); +XMLPUBFUN int XMLCALL + xmlSwitchInputEncoding (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input, + xmlCharEncodingHandlerPtr handler); + +#ifdef IN_LIBXML +/* internal error reporting */ +XMLPUBFUN void XMLCALL + __xmlErrEncoding (xmlParserCtxtPtr ctxt, + xmlParserErrors xmlerr, + const char *msg, + const xmlChar * str1, + const xmlChar * str2); +#endif + +/** + * Input Streams. + */ +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewStringInputStream (xmlParserCtxtPtr ctxt, + const xmlChar *buffer); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewEntityInputStream (xmlParserCtxtPtr ctxt, + xmlEntityPtr entity); +XMLPUBFUN int XMLCALL + xmlPushInput (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN xmlChar XMLCALL + xmlPopInput (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlFreeInputStream (xmlParserInputPtr input); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewInputFromFile (xmlParserCtxtPtr ctxt, + const char *filename); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewInputStream (xmlParserCtxtPtr ctxt); + +/** + * Namespaces. + */ +XMLPUBFUN xmlChar * XMLCALL + xmlSplitQName (xmlParserCtxtPtr ctxt, + const xmlChar *name, + xmlChar **prefix); + +/** + * Generic production rules. + */ +XMLPUBFUN const xmlChar * XMLCALL + xmlParseName (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseNmtoken (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseEntityValue (xmlParserCtxtPtr ctxt, + xmlChar **orig); +XMLPUBFUN xmlChar * XMLCALL + xmlParseAttValue (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseSystemLiteral (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParsePubidLiteral (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseCharData (xmlParserCtxtPtr ctxt, + int cdata); +XMLPUBFUN xmlChar * XMLCALL + xmlParseExternalID (xmlParserCtxtPtr ctxt, + xmlChar **publicID, + int strict); +XMLPUBFUN void XMLCALL + xmlParseComment (xmlParserCtxtPtr ctxt); +XMLPUBFUN const xmlChar * XMLCALL + xmlParsePITarget (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParsePI (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseNotationDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseEntityDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseDefaultDecl (xmlParserCtxtPtr ctxt, + xmlChar **value); +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlParseNotationType (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlParseEnumerationType (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseEnumeratedType (xmlParserCtxtPtr ctxt, + xmlEnumerationPtr *tree); +XMLPUBFUN int XMLCALL + xmlParseAttributeType (xmlParserCtxtPtr ctxt, + xmlEnumerationPtr *tree); +XMLPUBFUN void XMLCALL + xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlParseElementMixedContentDecl + (xmlParserCtxtPtr ctxt, + int inputchk); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlParseElementChildrenContentDecl + (xmlParserCtxtPtr ctxt, + int inputchk); +XMLPUBFUN int XMLCALL + xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, + const xmlChar *name, + xmlElementContentPtr *result); +XMLPUBFUN int XMLCALL + xmlParseElementDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseMarkupDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseCharRef (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlParseEntityRef (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseReference (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParsePEReference (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseDocTypeDecl (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN const xmlChar * XMLCALL + xmlParseAttribute (xmlParserCtxtPtr ctxt, + xmlChar **value); +XMLPUBFUN const xmlChar * XMLCALL + xmlParseStartTag (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseEndTag (xmlParserCtxtPtr ctxt); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN void XMLCALL + xmlParseCDSect (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseContent (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseElement (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseVersionNum (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseVersionInfo (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseEncName (xmlParserCtxtPtr ctxt); +XMLPUBFUN const xmlChar * XMLCALL + xmlParseEncodingDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseSDDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseXMLDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseTextDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseMisc (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseExternalSubset (xmlParserCtxtPtr ctxt, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * XML_SUBSTITUTE_NONE: + * + * If no entities need to be substituted. + */ +#define XML_SUBSTITUTE_NONE 0 +/** + * XML_SUBSTITUTE_REF: + * + * Whether general entities need to be substituted. + */ +#define XML_SUBSTITUTE_REF 1 +/** + * XML_SUBSTITUTE_PEREF: + * + * Whether parameter entities need to be substituted. + */ +#define XML_SUBSTITUTE_PEREF 2 +/** + * XML_SUBSTITUTE_BOTH: + * + * Both general and parameter entities need to be substituted. + */ +#define XML_SUBSTITUTE_BOTH 3 + +XMLPUBFUN xmlChar * XMLCALL + xmlStringDecodeEntities (xmlParserCtxtPtr ctxt, + const xmlChar *str, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); +XMLPUBFUN xmlChar * XMLCALL + xmlStringLenDecodeEntities (xmlParserCtxtPtr ctxt, + const xmlChar *str, + int len, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); + +/* + * Generated by MACROS on top of parser.c c.f. PUSH_AND_POP. + */ +XMLPUBFUN int XMLCALL nodePush (xmlParserCtxtPtr ctxt, + xmlNodePtr value); +XMLPUBFUN xmlNodePtr XMLCALL nodePop (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL inputPush (xmlParserCtxtPtr ctxt, + xmlParserInputPtr value); +XMLPUBFUN xmlParserInputPtr XMLCALL inputPop (xmlParserCtxtPtr ctxt); +XMLPUBFUN const xmlChar * XMLCALL namePop (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL namePush (xmlParserCtxtPtr ctxt, + const xmlChar *value); + +/* + * other commodities shared between parser.c and parserInternals. + */ +XMLPUBFUN int XMLCALL xmlSkipBlankChars (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL xmlStringCurrentChar (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + int *len); +XMLPUBFUN void XMLCALL xmlParserHandlePEReference(xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL xmlCheckLanguageID (const xmlChar *lang); + +/* + * Really core function shared with HTML parser. + */ +XMLPUBFUN int XMLCALL xmlCurrentChar (xmlParserCtxtPtr ctxt, + int *len); +XMLPUBFUN int XMLCALL xmlCopyCharMultiByte (xmlChar *out, + int val); +XMLPUBFUN int XMLCALL xmlCopyChar (int len, + xmlChar *out, + int val); +XMLPUBFUN void XMLCALL xmlNextChar (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL xmlParserInputShrink (xmlParserInputPtr in); + +#ifdef LIBXML_HTML_ENABLED +/* + * Actually comes from the HTML parser but launched from the init stuff. + */ +XMLPUBFUN void XMLCALL htmlInitAutoClose (void); +XMLPUBFUN htmlParserCtxtPtr XMLCALL htmlCreateFileParserCtxt(const char *filename, + const char *encoding); +#endif + +/* + * Specific function to keep track of entities references + * and used by the XSLT debugger. + */ +#ifdef LIBXML_LEGACY_ENABLED +/** + * xmlEntityReferenceFunc: + * @ent: the entity + * @firstNode: the fist node in the chunk + * @lastNode: the last nod in the chunk + * + * Callback function used when one needs to be able to track back the + * provenance of a chunk of nodes inherited from an entity replacement. + */ +typedef void (*xmlEntityReferenceFunc) (xmlEntityPtr ent, + xmlNodePtr firstNode, + xmlNodePtr lastNode); + +XMLPUBFUN void XMLCALL xmlSetEntityReferenceFunc (xmlEntityReferenceFunc func); + +XMLPUBFUN xmlChar * XMLCALL + xmlParseQuotedString (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseNamespace (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlNamespaceParseNSDef (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlScanName (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlNamespaceParseNCName (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL xmlParserHandleReference(xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlNamespaceParseQName (xmlParserCtxtPtr ctxt, + xmlChar **prefix); +/** + * Entities + */ +XMLPUBFUN xmlChar * XMLCALL + xmlDecodeEntities (xmlParserCtxtPtr ctxt, + int len, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); +XMLPUBFUN void XMLCALL + xmlHandleEntity (xmlParserCtxtPtr ctxt, + xmlEntityPtr entity); + +#endif /* LIBXML_LEGACY_ENABLED */ + +#ifdef IN_LIBXML +/* + * internal only + */ +XMLPUBFUN void XMLCALL + xmlErrMemory (xmlParserCtxtPtr ctxt, + const char *extra); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __XML_PARSER_INTERNALS_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/pattern.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/pattern.h new file mode 100644 index 0000000..97d2cd2 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/pattern.h @@ -0,0 +1,100 @@ +/* + * Summary: pattern expression handling + * Description: allows to compile and test pattern expressions for nodes + * either in a tree or based on a parser state. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PATTERN_H__ +#define __XML_PATTERN_H__ + +#include +#include +#include + +#ifdef LIBXML_PATTERN_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlPattern: + * + * A compiled (XPath based) pattern to select nodes + */ +typedef struct _xmlPattern xmlPattern; +typedef xmlPattern *xmlPatternPtr; + +/** + * xmlPatternFlags: + * + * This is the set of options affecting the behaviour of pattern + * matching with this module + * + */ +typedef enum { + XML_PATTERN_DEFAULT = 0, /* simple pattern match */ + XML_PATTERN_XPATH = 1<<0, /* standard XPath pattern */ + XML_PATTERN_XSSEL = 1<<1, /* XPath subset for schema selector */ + XML_PATTERN_XSFIELD = 1<<2 /* XPath subset for schema field */ +} xmlPatternFlags; + +XMLPUBFUN void XMLCALL + xmlFreePattern (xmlPatternPtr comp); + +XMLPUBFUN void XMLCALL + xmlFreePatternList (xmlPatternPtr comp); + +XMLPUBFUN xmlPatternPtr XMLCALL + xmlPatterncompile (const xmlChar *pattern, + xmlDict *dict, + int flags, + const xmlChar **namespaces); +XMLPUBFUN int XMLCALL + xmlPatternMatch (xmlPatternPtr comp, + xmlNodePtr node); + +/* streaming interfaces */ +typedef struct _xmlStreamCtxt xmlStreamCtxt; +typedef xmlStreamCtxt *xmlStreamCtxtPtr; + +XMLPUBFUN int XMLCALL + xmlPatternStreamable (xmlPatternPtr comp); +XMLPUBFUN int XMLCALL + xmlPatternMaxDepth (xmlPatternPtr comp); +XMLPUBFUN int XMLCALL + xmlPatternMinDepth (xmlPatternPtr comp); +XMLPUBFUN int XMLCALL + xmlPatternFromRoot (xmlPatternPtr comp); +XMLPUBFUN xmlStreamCtxtPtr XMLCALL + xmlPatternGetStreamCtxt (xmlPatternPtr comp); +XMLPUBFUN void XMLCALL + xmlFreeStreamCtxt (xmlStreamCtxtPtr stream); +XMLPUBFUN int XMLCALL + xmlStreamPushNode (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns, + int nodeType); +XMLPUBFUN int XMLCALL + xmlStreamPush (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int XMLCALL + xmlStreamPushAttr (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int XMLCALL + xmlStreamPop (xmlStreamCtxtPtr stream); +XMLPUBFUN int XMLCALL + xmlStreamWantsAnyNode (xmlStreamCtxtPtr stream); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_PATTERN_ENABLED */ + +#endif /* __XML_PATTERN_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/relaxng.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/relaxng.h new file mode 100644 index 0000000..f269c9e --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/relaxng.h @@ -0,0 +1,217 @@ +/* + * Summary: implementation of the Relax-NG validation + * Description: implementation of the Relax-NG validation + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_RELAX_NG__ +#define __XML_RELAX_NG__ + +#include +#include +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlRelaxNG xmlRelaxNG; +typedef xmlRelaxNG *xmlRelaxNGPtr; + + +/** + * xmlRelaxNGValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from a Relax-NG validation + */ +typedef void (XMLCDECL *xmlRelaxNGValidityErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlRelaxNGValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from a Relax-NG validation + */ +typedef void (XMLCDECL *xmlRelaxNGValidityWarningFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * A schemas validation context + */ +typedef struct _xmlRelaxNGParserCtxt xmlRelaxNGParserCtxt; +typedef xmlRelaxNGParserCtxt *xmlRelaxNGParserCtxtPtr; + +typedef struct _xmlRelaxNGValidCtxt xmlRelaxNGValidCtxt; +typedef xmlRelaxNGValidCtxt *xmlRelaxNGValidCtxtPtr; + +/* + * xmlRelaxNGValidErr: + * + * List of possible Relax NG validation errors + */ +typedef enum { + XML_RELAXNG_OK = 0, + XML_RELAXNG_ERR_MEMORY, + XML_RELAXNG_ERR_TYPE, + XML_RELAXNG_ERR_TYPEVAL, + XML_RELAXNG_ERR_DUPID, + XML_RELAXNG_ERR_TYPECMP, + XML_RELAXNG_ERR_NOSTATE, + XML_RELAXNG_ERR_NODEFINE, + XML_RELAXNG_ERR_LISTEXTRA, + XML_RELAXNG_ERR_LISTEMPTY, + XML_RELAXNG_ERR_INTERNODATA, + XML_RELAXNG_ERR_INTERSEQ, + XML_RELAXNG_ERR_INTEREXTRA, + XML_RELAXNG_ERR_ELEMNAME, + XML_RELAXNG_ERR_ATTRNAME, + XML_RELAXNG_ERR_ELEMNONS, + XML_RELAXNG_ERR_ATTRNONS, + XML_RELAXNG_ERR_ELEMWRONGNS, + XML_RELAXNG_ERR_ATTRWRONGNS, + XML_RELAXNG_ERR_ELEMEXTRANS, + XML_RELAXNG_ERR_ATTREXTRANS, + XML_RELAXNG_ERR_ELEMNOTEMPTY, + XML_RELAXNG_ERR_NOELEM, + XML_RELAXNG_ERR_NOTELEM, + XML_RELAXNG_ERR_ATTRVALID, + XML_RELAXNG_ERR_CONTENTVALID, + XML_RELAXNG_ERR_EXTRACONTENT, + XML_RELAXNG_ERR_INVALIDATTR, + XML_RELAXNG_ERR_DATAELEM, + XML_RELAXNG_ERR_VALELEM, + XML_RELAXNG_ERR_LISTELEM, + XML_RELAXNG_ERR_DATATYPE, + XML_RELAXNG_ERR_VALUE, + XML_RELAXNG_ERR_LIST, + XML_RELAXNG_ERR_NOGRAMMAR, + XML_RELAXNG_ERR_EXTRADATA, + XML_RELAXNG_ERR_LACKDATA, + XML_RELAXNG_ERR_INTERNAL, + XML_RELAXNG_ERR_ELEMWRONG, + XML_RELAXNG_ERR_TEXTWRONG +} xmlRelaxNGValidErr; + +/* + * xmlRelaxNGParserFlags: + * + * List of possible Relax NG Parser flags + */ +typedef enum { + XML_RELAXNGP_NONE = 0, + XML_RELAXNGP_FREE_DOC = 1, + XML_RELAXNGP_CRNG = 2 +} xmlRelaxNGParserFlag; + +XMLPUBFUN int XMLCALL + xmlRelaxNGInitTypes (void); +XMLPUBFUN void XMLCALL + xmlRelaxNGCleanupTypes (void); + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL + xmlRelaxNGNewParserCtxt (const char *URL); +XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL + xmlRelaxNGNewMemParserCtxt (const char *buffer, + int size); +XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL + xmlRelaxNGNewDocParserCtxt (xmlDocPtr doc); + +XMLPUBFUN int XMLCALL + xmlRelaxParserSetFlag (xmlRelaxNGParserCtxtPtr ctxt, + int flag); + +XMLPUBFUN void XMLCALL + xmlRelaxNGFreeParserCtxt (xmlRelaxNGParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc *err, + xmlRelaxNGValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN void XMLCALL + xmlRelaxNGSetParserStructuredErrors( + xmlRelaxNGParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN xmlRelaxNGPtr XMLCALL + xmlRelaxNGParse (xmlRelaxNGParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlRelaxNGFree (xmlRelaxNGPtr schema); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlRelaxNGDump (FILE *output, + xmlRelaxNGPtr schema); +XMLPUBFUN void XMLCALL + xmlRelaxNGDumpTree (FILE * output, + xmlRelaxNGPtr schema); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * Interfaces for validating + */ +XMLPUBFUN void XMLCALL + xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc *err, + xmlRelaxNGValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN void XMLCALL + xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, void *ctx); +XMLPUBFUN xmlRelaxNGValidCtxtPtr XMLCALL + xmlRelaxNGNewValidCtxt (xmlRelaxNGPtr schema); +XMLPUBFUN void XMLCALL + xmlRelaxNGFreeValidCtxt (xmlRelaxNGValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidateDoc (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc); +/* + * Interfaces for progressive validation when possible + */ +XMLPUBFUN int XMLCALL + xmlRelaxNGValidatePushElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidatePushCData (xmlRelaxNGValidCtxtPtr ctxt, + const xmlChar *data, + int len); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidatePopElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidateFullElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ + +#endif /* __XML_RELAX_NG__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/schemasInternals.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/schemasInternals.h new file mode 100644 index 0000000..c7cf552 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/schemasInternals.h @@ -0,0 +1,958 @@ +/* + * Summary: internal interfaces for XML Schemas + * Description: internal interfaces for the XML Schemas handling + * and schema validity checking + * The Schemas development is a Work In Progress. + * Some of those interfaces are not garanteed to be API or ABI stable ! + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_INTERNALS_H__ +#define __XML_SCHEMA_INTERNALS_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMAS_UNKNOWN = 0, + XML_SCHEMAS_STRING = 1, + XML_SCHEMAS_NORMSTRING = 2, + XML_SCHEMAS_DECIMAL = 3, + XML_SCHEMAS_TIME = 4, + XML_SCHEMAS_GDAY = 5, + XML_SCHEMAS_GMONTH = 6, + XML_SCHEMAS_GMONTHDAY = 7, + XML_SCHEMAS_GYEAR = 8, + XML_SCHEMAS_GYEARMONTH = 9, + XML_SCHEMAS_DATE = 10, + XML_SCHEMAS_DATETIME = 11, + XML_SCHEMAS_DURATION = 12, + XML_SCHEMAS_FLOAT = 13, + XML_SCHEMAS_DOUBLE = 14, + XML_SCHEMAS_BOOLEAN = 15, + XML_SCHEMAS_TOKEN = 16, + XML_SCHEMAS_LANGUAGE = 17, + XML_SCHEMAS_NMTOKEN = 18, + XML_SCHEMAS_NMTOKENS = 19, + XML_SCHEMAS_NAME = 20, + XML_SCHEMAS_QNAME = 21, + XML_SCHEMAS_NCNAME = 22, + XML_SCHEMAS_ID = 23, + XML_SCHEMAS_IDREF = 24, + XML_SCHEMAS_IDREFS = 25, + XML_SCHEMAS_ENTITY = 26, + XML_SCHEMAS_ENTITIES = 27, + XML_SCHEMAS_NOTATION = 28, + XML_SCHEMAS_ANYURI = 29, + XML_SCHEMAS_INTEGER = 30, + XML_SCHEMAS_NPINTEGER = 31, + XML_SCHEMAS_NINTEGER = 32, + XML_SCHEMAS_NNINTEGER = 33, + XML_SCHEMAS_PINTEGER = 34, + XML_SCHEMAS_INT = 35, + XML_SCHEMAS_UINT = 36, + XML_SCHEMAS_LONG = 37, + XML_SCHEMAS_ULONG = 38, + XML_SCHEMAS_SHORT = 39, + XML_SCHEMAS_USHORT = 40, + XML_SCHEMAS_BYTE = 41, + XML_SCHEMAS_UBYTE = 42, + XML_SCHEMAS_HEXBINARY = 43, + XML_SCHEMAS_BASE64BINARY = 44, + XML_SCHEMAS_ANYTYPE = 45, + XML_SCHEMAS_ANYSIMPLETYPE = 46 +} xmlSchemaValType; + +/* + * XML Schemas defines multiple type of types. + */ +typedef enum { + XML_SCHEMA_TYPE_BASIC = 1, /* A built-in datatype */ + XML_SCHEMA_TYPE_ANY, + XML_SCHEMA_TYPE_FACET, + XML_SCHEMA_TYPE_SIMPLE, + XML_SCHEMA_TYPE_COMPLEX, + XML_SCHEMA_TYPE_SEQUENCE = 6, + XML_SCHEMA_TYPE_CHOICE, + XML_SCHEMA_TYPE_ALL, + XML_SCHEMA_TYPE_SIMPLE_CONTENT, + XML_SCHEMA_TYPE_COMPLEX_CONTENT, + XML_SCHEMA_TYPE_UR, + XML_SCHEMA_TYPE_RESTRICTION, + XML_SCHEMA_TYPE_EXTENSION, + XML_SCHEMA_TYPE_ELEMENT, + XML_SCHEMA_TYPE_ATTRIBUTE, + XML_SCHEMA_TYPE_ATTRIBUTEGROUP, + XML_SCHEMA_TYPE_GROUP, + XML_SCHEMA_TYPE_NOTATION, + XML_SCHEMA_TYPE_LIST, + XML_SCHEMA_TYPE_UNION, + XML_SCHEMA_TYPE_ANY_ATTRIBUTE, + XML_SCHEMA_TYPE_IDC_UNIQUE, + XML_SCHEMA_TYPE_IDC_KEY, + XML_SCHEMA_TYPE_IDC_KEYREF, + XML_SCHEMA_TYPE_PARTICLE = 25, + XML_SCHEMA_TYPE_ATTRIBUTE_USE, + XML_SCHEMA_FACET_MININCLUSIVE = 1000, + XML_SCHEMA_FACET_MINEXCLUSIVE, + XML_SCHEMA_FACET_MAXINCLUSIVE, + XML_SCHEMA_FACET_MAXEXCLUSIVE, + XML_SCHEMA_FACET_TOTALDIGITS, + XML_SCHEMA_FACET_FRACTIONDIGITS, + XML_SCHEMA_FACET_PATTERN, + XML_SCHEMA_FACET_ENUMERATION, + XML_SCHEMA_FACET_WHITESPACE, + XML_SCHEMA_FACET_LENGTH, + XML_SCHEMA_FACET_MAXLENGTH, + XML_SCHEMA_FACET_MINLENGTH, + XML_SCHEMA_EXTRA_QNAMEREF = 2000, + XML_SCHEMA_EXTRA_ATTR_USE_PROHIB +} xmlSchemaTypeType; + +typedef enum { + XML_SCHEMA_CONTENT_UNKNOWN = 0, + XML_SCHEMA_CONTENT_EMPTY = 1, + XML_SCHEMA_CONTENT_ELEMENTS, + XML_SCHEMA_CONTENT_MIXED, + XML_SCHEMA_CONTENT_SIMPLE, + XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS, /* Obsolete */ + XML_SCHEMA_CONTENT_BASIC, + XML_SCHEMA_CONTENT_ANY +} xmlSchemaContentType; + +typedef struct _xmlSchemaVal xmlSchemaVal; +typedef xmlSchemaVal *xmlSchemaValPtr; + +typedef struct _xmlSchemaType xmlSchemaType; +typedef xmlSchemaType *xmlSchemaTypePtr; + +typedef struct _xmlSchemaFacet xmlSchemaFacet; +typedef xmlSchemaFacet *xmlSchemaFacetPtr; + +/** + * Annotation + */ +typedef struct _xmlSchemaAnnot xmlSchemaAnnot; +typedef xmlSchemaAnnot *xmlSchemaAnnotPtr; +struct _xmlSchemaAnnot { + struct _xmlSchemaAnnot *next; + xmlNodePtr content; /* the annotation */ +}; + +/** + * XML_SCHEMAS_ANYATTR_SKIP: + * + * Skip unknown attribute from validation + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_SKIP 1 +/** + * XML_SCHEMAS_ANYATTR_LAX: + * + * Ignore validation non definition on attributes + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_LAX 2 +/** + * XML_SCHEMAS_ANYATTR_STRICT: + * + * Apply strict validation rules on attributes + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_STRICT 3 +/** + * XML_SCHEMAS_ANY_SKIP: + * + * Skip unknown attribute from validation + */ +#define XML_SCHEMAS_ANY_SKIP 1 +/** + * XML_SCHEMAS_ANY_LAX: + * + * Used by wildcards. + * Validate if type found, don't worry if not found + */ +#define XML_SCHEMAS_ANY_LAX 2 +/** + * XML_SCHEMAS_ANY_STRICT: + * + * Used by wildcards. + * Apply strict validation rules + */ +#define XML_SCHEMAS_ANY_STRICT 3 +/** + * XML_SCHEMAS_ATTR_USE_PROHIBITED: + * + * Used by wildcards. + * The attribute is prohibited. + */ +#define XML_SCHEMAS_ATTR_USE_PROHIBITED 0 +/** + * XML_SCHEMAS_ATTR_USE_REQUIRED: + * + * The attribute is required. + */ +#define XML_SCHEMAS_ATTR_USE_REQUIRED 1 +/** + * XML_SCHEMAS_ATTR_USE_OPTIONAL: + * + * The attribute is optional. + */ +#define XML_SCHEMAS_ATTR_USE_OPTIONAL 2 +/** + * XML_SCHEMAS_ATTR_GLOBAL: + * + * allow elements in no namespace + */ +#define XML_SCHEMAS_ATTR_GLOBAL 1 << 0 +/** + * XML_SCHEMAS_ATTR_NSDEFAULT: + * + * allow elements in no namespace + */ +#define XML_SCHEMAS_ATTR_NSDEFAULT 1 << 7 +/** + * XML_SCHEMAS_ATTR_INTERNAL_RESOLVED: + * + * this is set when the "type" and "ref" references + * have been resolved. + */ +#define XML_SCHEMAS_ATTR_INTERNAL_RESOLVED 1 << 8 +/** + * XML_SCHEMAS_ATTR_FIXED: + * + * the attribute has a fixed value + */ +#define XML_SCHEMAS_ATTR_FIXED 1 << 9 + +/** + * xmlSchemaAttribute: + * An attribute definition. + */ + +typedef struct _xmlSchemaAttribute xmlSchemaAttribute; +typedef xmlSchemaAttribute *xmlSchemaAttributePtr; +struct _xmlSchemaAttribute { + xmlSchemaTypeType type; + struct _xmlSchemaAttribute *next; /* the next attribute (not used?) */ + const xmlChar *name; /* the name of the declaration */ + const xmlChar *id; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + const xmlChar *typeName; /* the local name of the type definition */ + const xmlChar *typeNs; /* the ns URI of the type definition */ + xmlSchemaAnnotPtr annot; + + xmlSchemaTypePtr base; /* Deprecated; not used */ + int occurs; /* Deprecated; not used */ + const xmlChar *defValue; /* The initial value of the value constraint */ + xmlSchemaTypePtr subtypes; /* the type definition */ + xmlNodePtr node; + const xmlChar *targetNamespace; + int flags; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaValPtr defVal; /* The compiled value constraint */ + xmlSchemaAttributePtr refDecl; /* Deprecated; not used */ +}; + +/** + * xmlSchemaAttributeLink: + * Used to build a list of attribute uses on complexType definitions. + * WARNING: Deprecated; not used. + */ +typedef struct _xmlSchemaAttributeLink xmlSchemaAttributeLink; +typedef xmlSchemaAttributeLink *xmlSchemaAttributeLinkPtr; +struct _xmlSchemaAttributeLink { + struct _xmlSchemaAttributeLink *next;/* the next attribute link ... */ + struct _xmlSchemaAttribute *attr;/* the linked attribute */ +}; + +/** + * XML_SCHEMAS_WILDCARD_COMPLETE: + * + * If the wildcard is complete. + */ +#define XML_SCHEMAS_WILDCARD_COMPLETE 1 << 0 + +/** + * xmlSchemaCharValueLink: + * Used to build a list of namespaces on wildcards. + */ +typedef struct _xmlSchemaWildcardNs xmlSchemaWildcardNs; +typedef xmlSchemaWildcardNs *xmlSchemaWildcardNsPtr; +struct _xmlSchemaWildcardNs { + struct _xmlSchemaWildcardNs *next;/* the next constraint link ... */ + const xmlChar *value;/* the value */ +}; + +/** + * xmlSchemaWildcard. + * A wildcard. + */ +typedef struct _xmlSchemaWildcard xmlSchemaWildcard; +typedef xmlSchemaWildcard *xmlSchemaWildcardPtr; +struct _xmlSchemaWildcard { + xmlSchemaTypeType type; /* The kind of type */ + const xmlChar *id; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + int processContents; + int any; /* Indicates if the ns constraint is of ##any */ + xmlSchemaWildcardNsPtr nsSet; /* The list of allowed namespaces */ + xmlSchemaWildcardNsPtr negNsSet; /* The negated namespace */ + int flags; +}; + +/** + * XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED: + * + * The attribute wildcard has been already builded. + */ +#define XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED 1 << 0 +/** + * XML_SCHEMAS_ATTRGROUP_GLOBAL: + * + * The attribute wildcard has been already builded. + */ +#define XML_SCHEMAS_ATTRGROUP_GLOBAL 1 << 1 +/** + * XML_SCHEMAS_ATTRGROUP_MARKED: + * + * Marks the attr group as marked; used for circular checks. + */ +#define XML_SCHEMAS_ATTRGROUP_MARKED 1 << 2 + +/** + * XML_SCHEMAS_ATTRGROUP_REDEFINED: + * + * The attr group was redefined. + */ +#define XML_SCHEMAS_ATTRGROUP_REDEFINED 1 << 3 +/** + * XML_SCHEMAS_ATTRGROUP_HAS_REFS: + * + * Whether this attr. group contains attr. group references. + */ +#define XML_SCHEMAS_ATTRGROUP_HAS_REFS 1 << 4 + +/** + * An attribute group definition. + * + * xmlSchemaAttribute and xmlSchemaAttributeGroup start of structures + * must be kept similar + */ +typedef struct _xmlSchemaAttributeGroup xmlSchemaAttributeGroup; +typedef xmlSchemaAttributeGroup *xmlSchemaAttributeGroupPtr; +struct _xmlSchemaAttributeGroup { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaAttribute *next;/* the next attribute if in a group ... */ + const xmlChar *name; + const xmlChar *id; + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + + xmlSchemaAttributePtr attributes; /* Deprecated; not used */ + xmlNodePtr node; + int flags; + xmlSchemaWildcardPtr attributeWildcard; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaAttributeGroupPtr refItem; /* Deprecated; not used */ + const xmlChar *targetNamespace; + void *attrUses; +}; + +/** + * xmlSchemaTypeLink: + * Used to build a list of types (e.g. member types of + * simpleType with variety "union"). + */ +typedef struct _xmlSchemaTypeLink xmlSchemaTypeLink; +typedef xmlSchemaTypeLink *xmlSchemaTypeLinkPtr; +struct _xmlSchemaTypeLink { + struct _xmlSchemaTypeLink *next;/* the next type link ... */ + xmlSchemaTypePtr type;/* the linked type */ +}; + +/** + * xmlSchemaFacetLink: + * Used to build a list of facets. + */ +typedef struct _xmlSchemaFacetLink xmlSchemaFacetLink; +typedef xmlSchemaFacetLink *xmlSchemaFacetLinkPtr; +struct _xmlSchemaFacetLink { + struct _xmlSchemaFacetLink *next;/* the next facet link ... */ + xmlSchemaFacetPtr facet;/* the linked facet */ +}; + +/** + * XML_SCHEMAS_TYPE_MIXED: + * + * the element content type is mixed + */ +#define XML_SCHEMAS_TYPE_MIXED 1 << 0 +/** + * XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION: + * + * the simple or complex type has a derivation method of "extension". + */ +#define XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION 1 << 1 +/** + * XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION: + * + * the simple or complex type has a derivation method of "restriction". + */ +#define XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION 1 << 2 +/** + * XML_SCHEMAS_TYPE_GLOBAL: + * + * the type is global + */ +#define XML_SCHEMAS_TYPE_GLOBAL 1 << 3 +/** + * XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD: + * + * the complexType owns an attribute wildcard, i.e. + * it can be freed by the complexType + */ +#define XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD 1 << 4 /* Obsolete. */ +/** + * XML_SCHEMAS_TYPE_VARIETY_ABSENT: + * + * the simpleType has a variety of "absent". + * TODO: Actually not necessary :-/, since if + * none of the variety flags occur then it's + * automatically absent. + */ +#define XML_SCHEMAS_TYPE_VARIETY_ABSENT 1 << 5 +/** + * XML_SCHEMAS_TYPE_VARIETY_LIST: + * + * the simpleType has a variety of "list". + */ +#define XML_SCHEMAS_TYPE_VARIETY_LIST 1 << 6 +/** + * XML_SCHEMAS_TYPE_VARIETY_UNION: + * + * the simpleType has a variety of "union". + */ +#define XML_SCHEMAS_TYPE_VARIETY_UNION 1 << 7 +/** + * XML_SCHEMAS_TYPE_VARIETY_ATOMIC: + * + * the simpleType has a variety of "union". + */ +#define XML_SCHEMAS_TYPE_VARIETY_ATOMIC 1 << 8 +/** + * XML_SCHEMAS_TYPE_FINAL_EXTENSION: + * + * the complexType has a final of "extension". + */ +#define XML_SCHEMAS_TYPE_FINAL_EXTENSION 1 << 9 +/** + * XML_SCHEMAS_TYPE_FINAL_RESTRICTION: + * + * the simpleType/complexType has a final of "restriction". + */ +#define XML_SCHEMAS_TYPE_FINAL_RESTRICTION 1 << 10 +/** + * XML_SCHEMAS_TYPE_FINAL_LIST: + * + * the simpleType has a final of "list". + */ +#define XML_SCHEMAS_TYPE_FINAL_LIST 1 << 11 +/** + * XML_SCHEMAS_TYPE_FINAL_UNION: + * + * the simpleType has a final of "union". + */ +#define XML_SCHEMAS_TYPE_FINAL_UNION 1 << 12 +/** + * XML_SCHEMAS_TYPE_FINAL_DEFAULT: + * + * the simpleType has a final of "default". + */ +#define XML_SCHEMAS_TYPE_FINAL_DEFAULT 1 << 13 +/** + * XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE: + * + * Marks the item as a builtin primitive. + */ +#define XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE 1 << 14 +/** + * XML_SCHEMAS_TYPE_MARKED: + * + * Marks the item as marked; used for circular checks. + */ +#define XML_SCHEMAS_TYPE_MARKED 1 << 16 +/** + * XML_SCHEMAS_TYPE_BLOCK_DEFAULT: + * + * the complexType did not specify 'block' so use the default of the + * item. + */ +#define XML_SCHEMAS_TYPE_BLOCK_DEFAULT 1 << 17 +/** + * XML_SCHEMAS_TYPE_BLOCK_EXTENSION: + * + * the complexType has a 'block' of "extension". + */ +#define XML_SCHEMAS_TYPE_BLOCK_EXTENSION 1 << 18 +/** + * XML_SCHEMAS_TYPE_BLOCK_RESTRICTION: + * + * the complexType has a 'block' of "restriction". + */ +#define XML_SCHEMAS_TYPE_BLOCK_RESTRICTION 1 << 19 +/** + * XML_SCHEMAS_TYPE_ABSTRACT: + * + * the simple/complexType is abstract. + */ +#define XML_SCHEMAS_TYPE_ABSTRACT 1 << 20 +/** + * XML_SCHEMAS_TYPE_FACETSNEEDVALUE: + * + * indicates if the facets need a computed value + */ +#define XML_SCHEMAS_TYPE_FACETSNEEDVALUE 1 << 21 +/** + * XML_SCHEMAS_TYPE_INTERNAL_RESOLVED: + * + * indicates that the type was typefixed + */ +#define XML_SCHEMAS_TYPE_INTERNAL_RESOLVED 1 << 22 +/** + * XML_SCHEMAS_TYPE_INTERNAL_INVALID: + * + * indicates that the type is invalid + */ +#define XML_SCHEMAS_TYPE_INTERNAL_INVALID 1 << 23 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE: + * + * a whitespace-facet value of "preserve" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE 1 << 24 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_REPLACE: + * + * a whitespace-facet value of "replace" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_REPLACE 1 << 25 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE: + * + * a whitespace-facet value of "collapse" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE 1 << 26 +/** + * XML_SCHEMAS_TYPE_HAS_FACETS: + * + * has facets + */ +#define XML_SCHEMAS_TYPE_HAS_FACETS 1 << 27 +/** + * XML_SCHEMAS_TYPE_NORMVALUENEEDED: + * + * indicates if the facets (pattern) need a normalized value + */ +#define XML_SCHEMAS_TYPE_NORMVALUENEEDED 1 << 28 + +/** + * XML_SCHEMAS_TYPE_FIXUP_1: + * + * First stage of fixup was done. + */ +#define XML_SCHEMAS_TYPE_FIXUP_1 1 << 29 + +/** + * XML_SCHEMAS_TYPE_REDEFINED: + * + * The type was redefined. + */ +#define XML_SCHEMAS_TYPE_REDEFINED 1 << 30 +/** + * XML_SCHEMAS_TYPE_REDEFINING: + * + * The type redefines an other type. + */ +/* #define XML_SCHEMAS_TYPE_REDEFINING 1 << 31 */ + +/** + * _xmlSchemaType: + * + * Schemas type definition. + */ +struct _xmlSchemaType { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaType *next; /* the next type if in a sequence ... */ + const xmlChar *name; + const xmlChar *id ; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlSchemaTypePtr subtypes; + xmlSchemaAttributePtr attributes; /* Deprecated; not used */ + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + + int flags; + xmlSchemaContentType contentType; + const xmlChar *base; /* Base type's local name */ + const xmlChar *baseNs; /* Base type's target namespace */ + xmlSchemaTypePtr baseType; /* The base type component */ + xmlSchemaFacetPtr facets; /* Local facets */ + struct _xmlSchemaType *redef; /* Deprecated; not used */ + int recurse; /* Obsolete */ + xmlSchemaAttributeLinkPtr *attributeUses; /* Deprecated; not used */ + xmlSchemaWildcardPtr attributeWildcard; + int builtInType; /* Type of built-in types. */ + xmlSchemaTypeLinkPtr memberTypes; /* member-types if a union type. */ + xmlSchemaFacetLinkPtr facetSet; /* All facets (incl. inherited) */ + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaTypePtr contentTypeDef; /* Used for the simple content of complex types. + Could we use @subtypes for this? */ + xmlRegexpPtr contModel; /* Holds the automaton of the content model */ + const xmlChar *targetNamespace; + void *attrUses; +}; + +/* + * xmlSchemaElement: + * An element definition. + * + * xmlSchemaType, xmlSchemaFacet and xmlSchemaElement start of + * structures must be kept similar + */ +/** + * XML_SCHEMAS_ELEM_NILLABLE: + * + * the element is nillable + */ +#define XML_SCHEMAS_ELEM_NILLABLE 1 << 0 +/** + * XML_SCHEMAS_ELEM_GLOBAL: + * + * the element is global + */ +#define XML_SCHEMAS_ELEM_GLOBAL 1 << 1 +/** + * XML_SCHEMAS_ELEM_DEFAULT: + * + * the element has a default value + */ +#define XML_SCHEMAS_ELEM_DEFAULT 1 << 2 +/** + * XML_SCHEMAS_ELEM_FIXED: + * + * the element has a fixed value + */ +#define XML_SCHEMAS_ELEM_FIXED 1 << 3 +/** + * XML_SCHEMAS_ELEM_ABSTRACT: + * + * the element is abstract + */ +#define XML_SCHEMAS_ELEM_ABSTRACT 1 << 4 +/** + * XML_SCHEMAS_ELEM_TOPLEVEL: + * + * the element is top level + * obsolete: use XML_SCHEMAS_ELEM_GLOBAL instead + */ +#define XML_SCHEMAS_ELEM_TOPLEVEL 1 << 5 +/** + * XML_SCHEMAS_ELEM_REF: + * + * the element is a reference to a type + */ +#define XML_SCHEMAS_ELEM_REF 1 << 6 +/** + * XML_SCHEMAS_ELEM_NSDEFAULT: + * + * allow elements in no namespace + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ELEM_NSDEFAULT 1 << 7 +/** + * XML_SCHEMAS_ELEM_INTERNAL_RESOLVED: + * + * this is set when "type", "ref", "substitutionGroup" + * references have been resolved. + */ +#define XML_SCHEMAS_ELEM_INTERNAL_RESOLVED 1 << 8 + /** + * XML_SCHEMAS_ELEM_CIRCULAR: + * + * a helper flag for the search of circular references. + */ +#define XML_SCHEMAS_ELEM_CIRCULAR 1 << 9 +/** + * XML_SCHEMAS_ELEM_BLOCK_ABSENT: + * + * the "block" attribute is absent + */ +#define XML_SCHEMAS_ELEM_BLOCK_ABSENT 1 << 10 +/** + * XML_SCHEMAS_ELEM_BLOCK_EXTENSION: + * + * disallowed substitutions are absent + */ +#define XML_SCHEMAS_ELEM_BLOCK_EXTENSION 1 << 11 +/** + * XML_SCHEMAS_ELEM_BLOCK_RESTRICTION: + * + * disallowed substitutions: "restriction" + */ +#define XML_SCHEMAS_ELEM_BLOCK_RESTRICTION 1 << 12 +/** + * XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION: + * + * disallowed substitutions: "substituion" + */ +#define XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION 1 << 13 +/** + * XML_SCHEMAS_ELEM_FINAL_ABSENT: + * + * substitution group exclusions are absent + */ +#define XML_SCHEMAS_ELEM_FINAL_ABSENT 1 << 14 +/** + * XML_SCHEMAS_ELEM_FINAL_EXTENSION: + * + * substitution group exclusions: "extension" + */ +#define XML_SCHEMAS_ELEM_FINAL_EXTENSION 1 << 15 +/** + * XML_SCHEMAS_ELEM_FINAL_RESTRICTION: + * + * substitution group exclusions: "restriction" + */ +#define XML_SCHEMAS_ELEM_FINAL_RESTRICTION 1 << 16 +/** + * XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD: + * + * the declaration is a substitution group head + */ +#define XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD 1 << 17 +/** + * XML_SCHEMAS_ELEM_INTERNAL_CHECKED: + * + * this is set when the elem decl has been checked against + * all constraints + */ +#define XML_SCHEMAS_ELEM_INTERNAL_CHECKED 1 << 18 + +typedef struct _xmlSchemaElement xmlSchemaElement; +typedef xmlSchemaElement *xmlSchemaElementPtr; +struct _xmlSchemaElement { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaType *next; /* Not used? */ + const xmlChar *name; + const xmlChar *id; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlSchemaTypePtr subtypes; /* the type definition */ + xmlSchemaAttributePtr attributes; + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + + int flags; + const xmlChar *targetNamespace; + const xmlChar *namedType; + const xmlChar *namedTypeNs; + const xmlChar *substGroup; + const xmlChar *substGroupNs; + const xmlChar *scope; + const xmlChar *value; /* The original value of the value constraint. */ + struct _xmlSchemaElement *refDecl; /* This will now be used for the + substitution group affiliation */ + xmlRegexpPtr contModel; /* Obsolete for WXS, maybe used for RelaxNG */ + xmlSchemaContentType contentType; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaValPtr defVal; /* The compiled value contraint. */ + void *idcs; /* The identity-constraint defs */ +}; + +/* + * XML_SCHEMAS_FACET_UNKNOWN: + * + * unknown facet handling + */ +#define XML_SCHEMAS_FACET_UNKNOWN 0 +/* + * XML_SCHEMAS_FACET_PRESERVE: + * + * preserve the type of the facet + */ +#define XML_SCHEMAS_FACET_PRESERVE 1 +/* + * XML_SCHEMAS_FACET_REPLACE: + * + * replace the type of the facet + */ +#define XML_SCHEMAS_FACET_REPLACE 2 +/* + * XML_SCHEMAS_FACET_COLLAPSE: + * + * collapse the types of the facet + */ +#define XML_SCHEMAS_FACET_COLLAPSE 3 +/** + * A facet definition. + */ +struct _xmlSchemaFacet { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaFacet *next;/* the next type if in a sequence ... */ + const xmlChar *value; /* The original value */ + const xmlChar *id; /* Obsolete */ + xmlSchemaAnnotPtr annot; + xmlNodePtr node; + int fixed; /* XML_SCHEMAS_FACET_PRESERVE, etc. */ + int whitespace; + xmlSchemaValPtr val; /* The compiled value */ + xmlRegexpPtr regexp; /* The regex for patterns */ +}; + +/** + * A notation definition. + */ +typedef struct _xmlSchemaNotation xmlSchemaNotation; +typedef xmlSchemaNotation *xmlSchemaNotationPtr; +struct _xmlSchemaNotation { + xmlSchemaTypeType type; /* The kind of type */ + const xmlChar *name; + xmlSchemaAnnotPtr annot; + const xmlChar *identifier; + const xmlChar *targetNamespace; +}; + +/* +* TODO: Actually all those flags used for the schema should sit +* on the schema parser context, since they are used only +* during parsing an XML schema document, and not available +* on the component level as per spec. +*/ +/** + * XML_SCHEMAS_QUALIF_ELEM: + * + * Reflects elementFormDefault == qualified in + * an XML schema document. + */ +#define XML_SCHEMAS_QUALIF_ELEM 1 << 0 +/** + * XML_SCHEMAS_QUALIF_ATTR: + * + * Reflects attributeFormDefault == qualified in + * an XML schema document. + */ +#define XML_SCHEMAS_QUALIF_ATTR 1 << 1 +/** + * XML_SCHEMAS_FINAL_DEFAULT_EXTENSION: + * + * the schema has "extension" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_EXTENSION 1 << 2 +/** + * XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION: + * + * the schema has "restriction" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION 1 << 3 +/** + * XML_SCHEMAS_FINAL_DEFAULT_LIST: + * + * the cshema has "list" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_LIST 1 << 4 +/** + * XML_SCHEMAS_FINAL_DEFAULT_UNION: + * + * the schema has "union" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_UNION 1 << 5 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION: + * + * the schema has "extension" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION 1 << 6 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION: + * + * the schema has "restriction" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION 1 << 7 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION: + * + * the schema has "substitution" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION 1 << 8 +/** + * XML_SCHEMAS_INCLUDING_CONVERT_NS: + * + * the schema is currently including an other schema with + * no target namespace. + */ +#define XML_SCHEMAS_INCLUDING_CONVERT_NS 1 << 9 +/** + * _xmlSchema: + * + * A Schemas definition + */ +struct _xmlSchema { + const xmlChar *name; /* schema name */ + const xmlChar *targetNamespace; /* the target namespace */ + const xmlChar *version; + const xmlChar *id; /* Obsolete */ + xmlDocPtr doc; + xmlSchemaAnnotPtr annot; + int flags; + + xmlHashTablePtr typeDecl; + xmlHashTablePtr attrDecl; + xmlHashTablePtr attrgrpDecl; + xmlHashTablePtr elemDecl; + xmlHashTablePtr notaDecl; + + xmlHashTablePtr schemasImports; + + void *_private; /* unused by the library for users or bindings */ + xmlHashTablePtr groupDecl; + xmlDictPtr dict; + void *includes; /* the includes, this is opaque for now */ + int preserve; /* whether to free the document */ + int counter; /* used to give ononymous components unique names */ + xmlHashTablePtr idcDef; /* All identity-constraint defs. */ + void *volatiles; /* Obsolete */ +}; + +XMLPUBFUN void XMLCALL xmlSchemaFreeType (xmlSchemaTypePtr type); +XMLPUBFUN void XMLCALL xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_INTERNALS_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/schematron.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/schematron.h new file mode 100644 index 0000000..364eaec --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/schematron.h @@ -0,0 +1,142 @@ +/* + * Summary: XML Schemastron implementation + * Description: interface to the XML Schematron validity checking. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMATRON_H__ +#define __XML_SCHEMATRON_H__ + +#include + +#ifdef LIBXML_SCHEMATRON_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMATRON_OUT_QUIET = 1 << 0, /* quiet no report */ + XML_SCHEMATRON_OUT_TEXT = 1 << 1, /* build a textual report */ + XML_SCHEMATRON_OUT_XML = 1 << 2, /* output SVRL */ + XML_SCHEMATRON_OUT_ERROR = 1 << 3, /* output via xmlStructuredErrorFunc */ + XML_SCHEMATRON_OUT_FILE = 1 << 8, /* output to a file descriptor */ + XML_SCHEMATRON_OUT_BUFFER = 1 << 9, /* output to a buffer */ + XML_SCHEMATRON_OUT_IO = 1 << 10 /* output to I/O mechanism */ +} xmlSchematronValidOptions; + +/** + * The schemas related types are kept internal + */ +typedef struct _xmlSchematron xmlSchematron; +typedef xmlSchematron *xmlSchematronPtr; + +/** + * xmlSchematronValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from a Schematron validation + */ +typedef void (*xmlSchematronValidityErrorFunc) (void *ctx, const char *msg, ...); + +/** + * xmlSchematronValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from a Schematron validation + */ +typedef void (*xmlSchematronValidityWarningFunc) (void *ctx, const char *msg, ...); + +/** + * A schemas validation context + */ +typedef struct _xmlSchematronParserCtxt xmlSchematronParserCtxt; +typedef xmlSchematronParserCtxt *xmlSchematronParserCtxtPtr; + +typedef struct _xmlSchematronValidCtxt xmlSchematronValidCtxt; +typedef xmlSchematronValidCtxt *xmlSchematronValidCtxtPtr; + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL + xmlSchematronNewParserCtxt (const char *URL); +XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL + xmlSchematronNewMemParserCtxt(const char *buffer, + int size); +XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL + xmlSchematronNewDocParserCtxt(xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSchematronFreeParserCtxt (xmlSchematronParserCtxtPtr ctxt); +/***** +XMLPUBFUN void XMLCALL + xmlSchematronSetParserErrors(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronValidityErrorFunc err, + xmlSchematronValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchematronGetParserErrors(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronValidityErrorFunc * err, + xmlSchematronValidityWarningFunc * warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchematronIsValid (xmlSchematronValidCtxtPtr ctxt); + *****/ +XMLPUBFUN xmlSchematronPtr XMLCALL + xmlSchematronParse (xmlSchematronParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlSchematronFree (xmlSchematronPtr schema); +/* + * Interfaces for validating + */ +XMLPUBFUN void XMLCALL + xmlSchematronSetValidStructuredErrors( + xmlSchematronValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +/****** +XMLPUBFUN void XMLCALL + xmlSchematronSetValidErrors (xmlSchematronValidCtxtPtr ctxt, + xmlSchematronValidityErrorFunc err, + xmlSchematronValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchematronGetValidErrors (xmlSchematronValidCtxtPtr ctxt, + xmlSchematronValidityErrorFunc *err, + xmlSchematronValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchematronSetValidOptions(xmlSchematronValidCtxtPtr ctxt, + int options); +XMLPUBFUN int XMLCALL + xmlSchematronValidCtxtGetOptions(xmlSchematronValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSchematronValidateOneElement (xmlSchematronValidCtxtPtr ctxt, + xmlNodePtr elem); + *******/ + +XMLPUBFUN xmlSchematronValidCtxtPtr XMLCALL + xmlSchematronNewValidCtxt (xmlSchematronPtr schema, + int options); +XMLPUBFUN void XMLCALL + xmlSchematronFreeValidCtxt (xmlSchematronValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSchematronValidateDoc (xmlSchematronValidCtxtPtr ctxt, + xmlDocPtr instance); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMATRON_ENABLED */ +#endif /* __XML_SCHEMATRON_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/threads.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/threads.h new file mode 100644 index 0000000..d31f16a --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/threads.h @@ -0,0 +1,84 @@ +/** + * Summary: interfaces for thread handling + * Description: set of generic threading related routines + * should work with pthreads, Windows native or TLS threads + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_THREADS_H__ +#define __XML_THREADS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * xmlMutex are a simple mutual exception locks. + */ +typedef struct _xmlMutex xmlMutex; +typedef xmlMutex *xmlMutexPtr; + +/* + * xmlRMutex are reentrant mutual exception locks. + */ +typedef struct _xmlRMutex xmlRMutex; +typedef xmlRMutex *xmlRMutexPtr; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN xmlMutexPtr XMLCALL + xmlNewMutex (void); +XMLPUBFUN void XMLCALL + xmlMutexLock (xmlMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlMutexUnlock (xmlMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlFreeMutex (xmlMutexPtr tok); + +XMLPUBFUN xmlRMutexPtr XMLCALL + xmlNewRMutex (void); +XMLPUBFUN void XMLCALL + xmlRMutexLock (xmlRMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlRMutexUnlock (xmlRMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlFreeRMutex (xmlRMutexPtr tok); + +/* + * Library wide APIs. + */ +XMLPUBFUN void XMLCALL + xmlInitThreads (void); +XMLPUBFUN void XMLCALL + xmlLockLibrary (void); +XMLPUBFUN void XMLCALL + xmlUnlockLibrary(void); +XMLPUBFUN int XMLCALL + xmlGetThreadId (void); +XMLPUBFUN int XMLCALL + xmlIsMainThread (void); +XMLPUBFUN void XMLCALL + xmlCleanupThreads(void); +XMLPUBFUN xmlGlobalStatePtr XMLCALL + xmlGetGlobalState(void); + +#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && defined(LIBXML_STATIC_FOR_DLL) +int XMLCALL xmlDllMain(void *hinstDLL, unsigned long fdwReason, void *lpvReserved); +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* __XML_THREADS_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/tree.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/tree.h new file mode 100644 index 0000000..4a9b3bc --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/tree.h @@ -0,0 +1,1311 @@ +/* + * Summary: interfaces for tree manipulation + * Description: this module describes the structures found in an tree resulting + * from an XML or HTML parsing, as well as the API provided for + * various processing on that tree + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_TREE_H__ +#define __XML_TREE_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Some of the basic types pointer to structures: + */ +/* xmlIO.h */ +typedef struct _xmlParserInputBuffer xmlParserInputBuffer; +typedef xmlParserInputBuffer *xmlParserInputBufferPtr; + +typedef struct _xmlOutputBuffer xmlOutputBuffer; +typedef xmlOutputBuffer *xmlOutputBufferPtr; + +/* parser.h */ +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; + +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; + +typedef struct _xmlSAXLocator xmlSAXLocator; +typedef xmlSAXLocator *xmlSAXLocatorPtr; + +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef xmlSAXHandler *xmlSAXHandlerPtr; + +/* entities.h */ +typedef struct _xmlEntity xmlEntity; +typedef xmlEntity *xmlEntityPtr; + +/** + * BASE_BUFFER_SIZE: + * + * default buffer size 4000. + */ +#define BASE_BUFFER_SIZE 4096 + +/** + * LIBXML_NAMESPACE_DICT: + * + * Defines experimental behaviour: + * 1) xmlNs gets an additional field @context (a xmlDoc) + * 2) when creating a tree, xmlNs->href is stored in the dict of xmlDoc. + */ +/* #define LIBXML_NAMESPACE_DICT */ + +/** + * xmlBufferAllocationScheme: + * + * A buffer allocation scheme can be defined to either match exactly the + * need or double it's allocated size each time it is found too small. + */ + +typedef enum { + XML_BUFFER_ALLOC_DOUBLEIT, /* double each time one need to grow */ + XML_BUFFER_ALLOC_EXACT, /* grow only to the minimal size */ + XML_BUFFER_ALLOC_IMMUTABLE, /* immutable buffer */ + XML_BUFFER_ALLOC_IO, /* special allocation scheme used for I/O */ + XML_BUFFER_ALLOC_HYBRID, /* exact up to a threshold, and doubleit thereafter */ + XML_BUFFER_ALLOC_BOUNDED /* limit the upper size of the buffer */ +} xmlBufferAllocationScheme; + +/** + * xmlBuffer: + * + * A buffer structure, this old construct is limited to 2GB and + * is being deprecated, use API with xmlBuf instead + */ +typedef struct _xmlBuffer xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; +struct _xmlBuffer { + xmlChar *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ + xmlBufferAllocationScheme alloc; /* The realloc method */ + xmlChar *contentIO; /* in IO mode we may have a different base */ +}; + +/** + * xmlBuf: + * + * A buffer structure, new one, the actual structure internals are not public + */ + +typedef struct _xmlBuf xmlBuf; + +/** + * xmlBufPtr: + * + * A pointer to a buffer structure, the actual structure internals are not + * public + */ + +typedef xmlBuf *xmlBufPtr; + +/* + * A few public routines for xmlBuf. As those are expected to be used + * mostly internally the bulk of the routines are internal in buf.h + */ +XMLPUBFUN xmlChar* XMLCALL xmlBufContent (const xmlBuf* buf); +XMLPUBFUN xmlChar* XMLCALL xmlBufEnd (xmlBufPtr buf); +XMLPUBFUN size_t XMLCALL xmlBufUse (const xmlBufPtr buf); +XMLPUBFUN size_t XMLCALL xmlBufShrink (xmlBufPtr buf, size_t len); + +/* + * LIBXML2_NEW_BUFFER: + * + * Macro used to express that the API use the new buffers for + * xmlParserInputBuffer and xmlOutputBuffer. The change was + * introduced in 2.9.0. + */ +#define LIBXML2_NEW_BUFFER + +/** + * XML_XML_NAMESPACE: + * + * This is the namespace for the special xml: prefix predefined in the + * XML Namespace specification. + */ +#define XML_XML_NAMESPACE \ + (const xmlChar *) "http://www.w3.org/XML/1998/namespace" + +/** + * XML_XML_ID: + * + * This is the name for the special xml:id attribute + */ +#define XML_XML_ID (const xmlChar *) "xml:id" + +/* + * The different element types carried by an XML tree. + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE= 1, + XML_ATTRIBUTE_NODE= 2, + XML_TEXT_NODE= 3, + XML_CDATA_SECTION_NODE= 4, + XML_ENTITY_REF_NODE= 5, + XML_ENTITY_NODE= 6, + XML_PI_NODE= 7, + XML_COMMENT_NODE= 8, + XML_DOCUMENT_NODE= 9, + XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_FRAG_NODE= 11, + XML_NOTATION_NODE= 12, + XML_HTML_DOCUMENT_NODE= 13, + XML_DTD_NODE= 14, + XML_ELEMENT_DECL= 15, + XML_ATTRIBUTE_DECL= 16, + XML_ENTITY_DECL= 17, + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 +#ifdef LIBXML_DOCB_ENABLED + ,XML_DOCB_DOCUMENT_NODE= 21 +#endif +} xmlElementType; + + +/** + * xmlNotation: + * + * A DTD Notation definition. + */ + +typedef struct _xmlNotation xmlNotation; +typedef xmlNotation *xmlNotationPtr; +struct _xmlNotation { + const xmlChar *name; /* Notation name */ + const xmlChar *PublicID; /* Public identifier, if any */ + const xmlChar *SystemID; /* System identifier, if any */ +}; + +/** + * xmlAttributeType: + * + * A DTD Attribute type definition. + */ + +typedef enum { + XML_ATTRIBUTE_CDATA = 1, + XML_ATTRIBUTE_ID, + XML_ATTRIBUTE_IDREF , + XML_ATTRIBUTE_IDREFS, + XML_ATTRIBUTE_ENTITY, + XML_ATTRIBUTE_ENTITIES, + XML_ATTRIBUTE_NMTOKEN, + XML_ATTRIBUTE_NMTOKENS, + XML_ATTRIBUTE_ENUMERATION, + XML_ATTRIBUTE_NOTATION +} xmlAttributeType; + +/** + * xmlAttributeDefault: + * + * A DTD Attribute default definition. + */ + +typedef enum { + XML_ATTRIBUTE_NONE = 1, + XML_ATTRIBUTE_REQUIRED, + XML_ATTRIBUTE_IMPLIED, + XML_ATTRIBUTE_FIXED +} xmlAttributeDefault; + +/** + * xmlEnumeration: + * + * List structure used when there is an enumeration in DTDs. + */ + +typedef struct _xmlEnumeration xmlEnumeration; +typedef xmlEnumeration *xmlEnumerationPtr; +struct _xmlEnumeration { + struct _xmlEnumeration *next; /* next one */ + const xmlChar *name; /* Enumeration name */ +}; + +/** + * xmlAttribute: + * + * An Attribute declaration in a DTD. + */ + +typedef struct _xmlAttribute xmlAttribute; +typedef xmlAttribute *xmlAttributePtr; +struct _xmlAttribute { + void *_private; /* application data */ + xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + struct _xmlAttribute *nexth; /* next in hash table */ + xmlAttributeType atype; /* The attribute type */ + xmlAttributeDefault def; /* the default */ + const xmlChar *defaultValue; /* or the default value */ + xmlEnumerationPtr tree; /* or the enumeration tree if any */ + const xmlChar *prefix; /* the namespace prefix if any */ + const xmlChar *elem; /* Element holding the attribute */ +}; + +/** + * xmlElementContentType: + * + * Possible definitions of element content types. + */ +typedef enum { + XML_ELEMENT_CONTENT_PCDATA = 1, + XML_ELEMENT_CONTENT_ELEMENT, + XML_ELEMENT_CONTENT_SEQ, + XML_ELEMENT_CONTENT_OR +} xmlElementContentType; + +/** + * xmlElementContentOccur: + * + * Possible definitions of element content occurrences. + */ +typedef enum { + XML_ELEMENT_CONTENT_ONCE = 1, + XML_ELEMENT_CONTENT_OPT, + XML_ELEMENT_CONTENT_MULT, + XML_ELEMENT_CONTENT_PLUS +} xmlElementContentOccur; + +/** + * xmlElementContent: + * + * An XML Element content as stored after parsing an element definition + * in a DTD. + */ + +typedef struct _xmlElementContent xmlElementContent; +typedef xmlElementContent *xmlElementContentPtr; +struct _xmlElementContent { + xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ + xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ + const xmlChar *name; /* Element name */ + struct _xmlElementContent *c1; /* first child */ + struct _xmlElementContent *c2; /* second child */ + struct _xmlElementContent *parent; /* parent */ + const xmlChar *prefix; /* Namespace prefix */ +}; + +/** + * xmlElementTypeVal: + * + * The different possibilities for an element content type. + */ + +typedef enum { + XML_ELEMENT_TYPE_UNDEFINED = 0, + XML_ELEMENT_TYPE_EMPTY = 1, + XML_ELEMENT_TYPE_ANY, + XML_ELEMENT_TYPE_MIXED, + XML_ELEMENT_TYPE_ELEMENT +} xmlElementTypeVal; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlElement: + * + * An XML Element declaration from a DTD. + */ + +typedef struct _xmlElement xmlElement; +typedef xmlElement *xmlElementPtr; +struct _xmlElement { + void *_private; /* application data */ + xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ + const xmlChar *name; /* Element name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlElementTypeVal etype; /* The type */ + xmlElementContentPtr content; /* the allowed element content */ + xmlAttributePtr attributes; /* List of the declared attributes */ + const xmlChar *prefix; /* the namespace prefix if any */ +#ifdef LIBXML_REGEXP_ENABLED + xmlRegexpPtr contModel; /* the validating regexp */ +#else + void *contModel; +#endif +}; + + +/** + * XML_LOCAL_NAMESPACE: + * + * A namespace declaration node. + */ +#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL +typedef xmlElementType xmlNsType; + +/** + * xmlNs: + * + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overridden). + * + * xmlNsType is unified with xmlElementType. + */ + +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ + void *_private; /* application data */ + struct _xmlDoc *context; /* normally an xmlDoc */ +}; + +/** + * xmlDtd: + * + * An XML DTD, as defined by parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + void *notations; /* Hash table for notations if any */ + void *elements; /* Hash table for elements if any */ + void *attributes; /* Hash table for attributes if any */ + void *entities; /* Hash table for entities if any */ + const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ + void *pentities; /* Hash table for param entities if any */ +}; + +/** + * xmlAttr: + * + * An attribute on an XML node. + */ +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +struct _xmlAttr { + void *_private; /* application data */ + xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ + const xmlChar *name; /* the name of the property */ + struct _xmlNode *children; /* the value of the property */ + struct _xmlNode *last; /* NULL */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlAttr *next; /* next sibling link */ + struct _xmlAttr *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlAttributeType atype; /* the attribute type if validating */ + void *psvi; /* for type/PSVI informations */ +}; + +/** + * xmlID: + * + * An XML ID instance. + */ + +typedef struct _xmlID xmlID; +typedef xmlID *xmlIDPtr; +struct _xmlID { + struct _xmlID *next; /* next ID */ + const xmlChar *value; /* The ID name */ + xmlAttrPtr attr; /* The attribute holding it */ + const xmlChar *name; /* The attribute if attr is not available */ + int lineno; /* The line number if attr is not available */ + struct _xmlDoc *doc; /* The document holding the ID */ +}; + +/** + * xmlRef: + * + * An XML IDREF instance. + */ + +typedef struct _xmlRef xmlRef; +typedef xmlRef *xmlRefPtr; +struct _xmlRef { + struct _xmlRef *next; /* next Ref */ + const xmlChar *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribute holding it */ + const xmlChar *name; /* The attribute if attr is not available */ + int lineno; /* The line number if attr is not available */ +}; + +/** + * xmlNode: + * + * A node in an XML tree. + */ +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +struct _xmlNode { + void *_private; /* application data */ + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlChar *content; /* the content */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ + void *psvi; /* for type/PSVI informations */ + unsigned short line; /* line number */ + unsigned short extra; /* extra data for XPath/XSLT */ +}; + +/** + * XML_GET_CONTENT: + * + * Macro to extract the content pointer of a node. + */ +#define XML_GET_CONTENT(n) \ + ((n)->type == XML_ELEMENT_NODE ? NULL : (n)->content) + +/** + * XML_GET_LINE: + * + * Macro to extract the line number of an element node. + */ +#define XML_GET_LINE(n) \ + (xmlGetLineNo(n)) + +/** + * xmlDocProperty + * + * Set of properties of the document as found by the parser + * Some of them are linked to similary named xmlParserOption + */ +typedef enum { + XML_DOC_WELLFORMED = 1<<0, /* document is XML well formed */ + XML_DOC_NSVALID = 1<<1, /* document is Namespace valid */ + XML_DOC_OLD10 = 1<<2, /* parsed with old XML-1.0 parser */ + XML_DOC_DTDVALID = 1<<3, /* DTD validation was successful */ + XML_DOC_XINCLUDE = 1<<4, /* XInclude substitution was done */ + XML_DOC_USERBUILT = 1<<5, /* Document was built using the API + and not by parsing an instance */ + XML_DOC_INTERNAL = 1<<6, /* built for internal processing */ + XML_DOC_HTML = 1<<7 /* parsed or built HTML document */ +} xmlDocProperties; + +/** + * xmlDoc: + * + * An XML document. + */ +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +struct _xmlDoc { + void *_private; /* application data */ + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) + 1 if standalone="yes" + 0 if standalone="no" + -1 if there is no XML declaration + -2 if there is an XML declaration, but no + standalone attribute was specified */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* external initial encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + struct _xmlDict *dict; /* dict used to allocate names or NULL */ + void *psvi; /* for type/PSVI informations */ + int parseFlags; /* set of xmlParserOption used to parse the + document */ + int properties; /* set of xmlDocProperties for this document + set at the end of parsing */ +}; + + +typedef struct _xmlDOMWrapCtxt xmlDOMWrapCtxt; +typedef xmlDOMWrapCtxt *xmlDOMWrapCtxtPtr; + +/** + * xmlDOMWrapAcquireNsFunction: + * @ctxt: a DOM wrapper context + * @node: the context node (element or attribute) + * @nsName: the requested namespace name + * @nsPrefix: the requested namespace prefix + * + * A function called to acquire namespaces (xmlNs) from the wrapper. + * + * Returns an xmlNsPtr or NULL in case of an error. + */ +typedef xmlNsPtr (*xmlDOMWrapAcquireNsFunction) (xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr node, + const xmlChar *nsName, + const xmlChar *nsPrefix); + +/** + * xmlDOMWrapCtxt: + * + * Context for DOM wrapper-operations. + */ +struct _xmlDOMWrapCtxt { + void * _private; + /* + * The type of this context, just in case we need specialized + * contexts in the future. + */ + int type; + /* + * Internal namespace map used for various operations. + */ + void * namespaceMap; + /* + * Use this one to acquire an xmlNsPtr intended for node->ns. + * (Note that this is not intended for elem->nsDef). + */ + xmlDOMWrapAcquireNsFunction getNsForNodeFunc; +}; + +/** + * xmlChildrenNode: + * + * Macro for compatibility naming layer with libxml1. Maps + * to "children." + */ +#ifndef xmlChildrenNode +#define xmlChildrenNode children +#endif + +/** + * xmlRootNode: + * + * Macro for compatibility naming layer with libxml1. Maps + * to "children". + */ +#ifndef xmlRootNode +#define xmlRootNode children +#endif + +/* + * Variables. + */ + +/* + * Some helper functions + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || \ + defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || \ + defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || \ + defined(LIBXML_DOCB_ENABLED) || defined(LIBXML_LEGACY_ENABLED) +XMLPUBFUN int XMLCALL + xmlValidateNCName (const xmlChar *value, + int space); +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int XMLCALL + xmlValidateQName (const xmlChar *value, + int space); +XMLPUBFUN int XMLCALL + xmlValidateName (const xmlChar *value, + int space); +XMLPUBFUN int XMLCALL + xmlValidateNMToken (const xmlChar *value, + int space); +#endif + +XMLPUBFUN xmlChar * XMLCALL + xmlBuildQName (const xmlChar *ncname, + const xmlChar *prefix, + xmlChar *memory, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlSplitQName2 (const xmlChar *name, + xmlChar **prefix); +XMLPUBFUN const xmlChar * XMLCALL + xmlSplitQName3 (const xmlChar *name, + int *len); + +/* + * Handling Buffers, the old ones see @xmlBuf for the new ones. + */ + +XMLPUBFUN void XMLCALL + xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme); +XMLPUBFUN xmlBufferAllocationScheme XMLCALL + xmlGetBufferAllocationScheme(void); + +XMLPUBFUN xmlBufferPtr XMLCALL + xmlBufferCreate (void); +XMLPUBFUN xmlBufferPtr XMLCALL + xmlBufferCreateSize (size_t size); +XMLPUBFUN xmlBufferPtr XMLCALL + xmlBufferCreateStatic (void *mem, + size_t size); +XMLPUBFUN int XMLCALL + xmlBufferResize (xmlBufferPtr buf, + unsigned int size); +XMLPUBFUN void XMLCALL + xmlBufferFree (xmlBufferPtr buf); +XMLPUBFUN int XMLCALL + xmlBufferDump (FILE *file, + xmlBufferPtr buf); +XMLPUBFUN int XMLCALL + xmlBufferAdd (xmlBufferPtr buf, + const xmlChar *str, + int len); +XMLPUBFUN int XMLCALL + xmlBufferAddHead (xmlBufferPtr buf, + const xmlChar *str, + int len); +XMLPUBFUN int XMLCALL + xmlBufferCat (xmlBufferPtr buf, + const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlBufferCCat (xmlBufferPtr buf, + const char *str); +XMLPUBFUN int XMLCALL + xmlBufferShrink (xmlBufferPtr buf, + unsigned int len); +XMLPUBFUN int XMLCALL + xmlBufferGrow (xmlBufferPtr buf, + unsigned int len); +XMLPUBFUN void XMLCALL + xmlBufferEmpty (xmlBufferPtr buf); +XMLPUBFUN const xmlChar* XMLCALL + xmlBufferContent (const xmlBuffer *buf); +XMLPUBFUN xmlChar* XMLCALL + xmlBufferDetach (xmlBufferPtr buf); +XMLPUBFUN void XMLCALL + xmlBufferSetAllocationScheme(xmlBufferPtr buf, + xmlBufferAllocationScheme scheme); +XMLPUBFUN int XMLCALL + xmlBufferLength (const xmlBuffer *buf); + +/* + * Creating/freeing new structures. + */ +XMLPUBFUN xmlDtdPtr XMLCALL + xmlCreateIntSubset (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlNewDtd (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlGetIntSubset (const xmlDoc *doc); +XMLPUBFUN void XMLCALL + xmlFreeDtd (xmlDtdPtr cur); +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN xmlNsPtr XMLCALL + xmlNewGlobalNs (xmlDocPtr doc, + const xmlChar *href, + const xmlChar *prefix); +#endif /* LIBXML_LEGACY_ENABLED */ +XMLPUBFUN xmlNsPtr XMLCALL + xmlNewNs (xmlNodePtr node, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + xmlFreeNs (xmlNsPtr cur); +XMLPUBFUN void XMLCALL + xmlFreeNsList (xmlNsPtr cur); +XMLPUBFUN xmlDocPtr XMLCALL + xmlNewDoc (const xmlChar *version); +XMLPUBFUN void XMLCALL + xmlFreeDoc (xmlDocPtr cur); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewDocProp (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *value); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *value); +#endif +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewNsPropEatName (xmlNodePtr node, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *value); +XMLPUBFUN void XMLCALL + xmlFreePropList (xmlAttrPtr cur); +XMLPUBFUN void XMLCALL + xmlFreeProp (xmlAttrPtr cur); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlCopyProp (xmlNodePtr target, + xmlAttrPtr cur); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlCopyPropList (xmlNodePtr target, + xmlAttrPtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlDtdPtr XMLCALL + xmlCopyDtd (xmlDtdPtr dtd); +#endif /* LIBXML_TREE_ENABLED */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlDocPtr XMLCALL + xmlCopyDoc (xmlDocPtr doc, + int recursive); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ +/* + * Creating new nodes. + */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocNode (xmlDocPtr doc, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocNodeEatName (xmlDocPtr doc, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewNode (xmlNsPtr ns, + const xmlChar *name); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewNodeEatName (xmlNsPtr ns, + xmlChar *name); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewChild (xmlNodePtr parent, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +#endif +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocText (const xmlDoc *doc, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewText (const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocPI (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewPI (const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocTextLen (xmlDocPtr doc, + const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewTextLen (const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocComment (xmlDocPtr doc, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewComment (const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewCDataBlock (xmlDocPtr doc, + const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewCharRef (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewReference (const xmlDoc *doc, + const xmlChar *name); +XMLPUBFUN xmlNodePtr XMLCALL + xmlCopyNode (xmlNodePtr node, + int recursive); +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocCopyNode (xmlNodePtr node, + xmlDocPtr doc, + int recursive); +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocCopyNodeList (xmlDocPtr doc, + xmlNodePtr node); +XMLPUBFUN xmlNodePtr XMLCALL + xmlCopyNodeList (xmlNodePtr node); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewTextChild (xmlNodePtr parent, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocRawNode (xmlDocPtr doc, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocFragment (xmlDocPtr doc); +#endif /* LIBXML_TREE_ENABLED */ + +/* + * Navigating. + */ +XMLPUBFUN long XMLCALL + xmlGetLineNo (const xmlNode *node); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) +XMLPUBFUN xmlChar * XMLCALL + xmlGetNodePath (const xmlNode *node); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocGetRootElement (const xmlDoc *doc); +XMLPUBFUN xmlNodePtr XMLCALL + xmlGetLastChild (const xmlNode *parent); +XMLPUBFUN int XMLCALL + xmlNodeIsText (const xmlNode *node); +XMLPUBFUN int XMLCALL + xmlIsBlankNode (const xmlNode *node); + +/* + * Changing the structure. + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocSetRootElement (xmlDocPtr doc, + xmlNodePtr root); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void XMLCALL + xmlNodeSetName (xmlNodePtr cur, + const xmlChar *name); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddChild (xmlNodePtr parent, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddChildList (xmlNodePtr parent, + xmlNodePtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlReplaceNode (xmlNodePtr old, + xmlNodePtr cur); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddPrevSibling (xmlNodePtr cur, + xmlNodePtr elem); +#endif /* LIBXML_TREE_ENABLED || LIBXML_HTML_ENABLED || LIBXML_SCHEMAS_ENABLED */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddSibling (xmlNodePtr cur, + xmlNodePtr elem); +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddNextSibling (xmlNodePtr cur, + xmlNodePtr elem); +XMLPUBFUN void XMLCALL + xmlUnlinkNode (xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextMerge (xmlNodePtr first, + xmlNodePtr second); +XMLPUBFUN int XMLCALL + xmlTextConcat (xmlNodePtr node, + const xmlChar *content, + int len); +XMLPUBFUN void XMLCALL + xmlFreeNodeList (xmlNodePtr cur); +XMLPUBFUN void XMLCALL + xmlFreeNode (xmlNodePtr cur); +XMLPUBFUN void XMLCALL + xmlSetTreeDoc (xmlNodePtr tree, + xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSetListDoc (xmlNodePtr list, + xmlDocPtr doc); +/* + * Namespaces. + */ +XMLPUBFUN xmlNsPtr XMLCALL + xmlSearchNs (xmlDocPtr doc, + xmlNodePtr node, + const xmlChar *nameSpace); +XMLPUBFUN xmlNsPtr XMLCALL + xmlSearchNsByHref (xmlDocPtr doc, + xmlNodePtr node, + const xmlChar *href); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlNsPtr * XMLCALL + xmlGetNsList (const xmlDoc *doc, + const xmlNode *node); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) */ + +XMLPUBFUN void XMLCALL + xmlSetNs (xmlNodePtr node, + xmlNsPtr ns); +XMLPUBFUN xmlNsPtr XMLCALL + xmlCopyNamespace (xmlNsPtr cur); +XMLPUBFUN xmlNsPtr XMLCALL + xmlCopyNamespaceList (xmlNsPtr cur); + +/* + * Changing the content. + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) +XMLPUBFUN xmlAttrPtr XMLCALL + xmlSetProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlSetNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *value); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) */ +XMLPUBFUN xmlChar * XMLCALL + xmlGetNoNsProp (const xmlNode *node, + const xmlChar *name); +XMLPUBFUN xmlChar * XMLCALL + xmlGetProp (const xmlNode *node, + const xmlChar *name); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlHasProp (const xmlNode *node, + const xmlChar *name); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlHasNsProp (const xmlNode *node, + const xmlChar *name, + const xmlChar *nameSpace); +XMLPUBFUN xmlChar * XMLCALL + xmlGetNsProp (const xmlNode *node, + const xmlChar *name, + const xmlChar *nameSpace); +XMLPUBFUN xmlNodePtr XMLCALL + xmlStringGetNodeList (const xmlDoc *doc, + const xmlChar *value); +XMLPUBFUN xmlNodePtr XMLCALL + xmlStringLenGetNodeList (const xmlDoc *doc, + const xmlChar *value, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlNodeListGetString (xmlDocPtr doc, + const xmlNode *list, + int inLine); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlChar * XMLCALL + xmlNodeListGetRawString (const xmlDoc *doc, + const xmlNode *list, + int inLine); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlNodeSetContent (xmlNodePtr cur, + const xmlChar *content); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void XMLCALL + xmlNodeSetContentLen (xmlNodePtr cur, + const xmlChar *content, + int len); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlNodeAddContent (xmlNodePtr cur, + const xmlChar *content); +XMLPUBFUN void XMLCALL + xmlNodeAddContentLen (xmlNodePtr cur, + const xmlChar *content, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlNodeGetContent (const xmlNode *cur); + +XMLPUBFUN int XMLCALL + xmlNodeBufGetContent (xmlBufferPtr buffer, + const xmlNode *cur); +XMLPUBFUN int XMLCALL + xmlBufGetNodeContent (xmlBufPtr buf, + const xmlNode *cur); + +XMLPUBFUN xmlChar * XMLCALL + xmlNodeGetLang (const xmlNode *cur); +XMLPUBFUN int XMLCALL + xmlNodeGetSpacePreserve (const xmlNode *cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void XMLCALL + xmlNodeSetLang (xmlNodePtr cur, + const xmlChar *lang); +XMLPUBFUN void XMLCALL + xmlNodeSetSpacePreserve (xmlNodePtr cur, + int val); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN xmlChar * XMLCALL + xmlNodeGetBase (const xmlDoc *doc, + const xmlNode *cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +XMLPUBFUN void XMLCALL + xmlNodeSetBase (xmlNodePtr cur, + const xmlChar *uri); +#endif + +/* + * Removing content. + */ +XMLPUBFUN int XMLCALL + xmlRemoveProp (xmlAttrPtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int XMLCALL + xmlUnsetNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name); +XMLPUBFUN int XMLCALL + xmlUnsetProp (xmlNodePtr node, + const xmlChar *name); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ + +/* + * Internal, don't use. + */ +XMLPUBFUN void XMLCALL + xmlBufferWriteCHAR (xmlBufferPtr buf, + const xmlChar *string); +XMLPUBFUN void XMLCALL + xmlBufferWriteChar (xmlBufferPtr buf, + const char *string); +XMLPUBFUN void XMLCALL + xmlBufferWriteQuotedString(xmlBufferPtr buf, + const xmlChar *string); + +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void xmlAttrSerializeTxtContent(xmlBufferPtr buf, + xmlDocPtr doc, + xmlAttrPtr attr, + const xmlChar *string); +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_TREE_ENABLED +/* + * Namespace handling. + */ +XMLPUBFUN int XMLCALL + xmlReconciliateNs (xmlDocPtr doc, + xmlNodePtr tree); +#endif + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Saving. + */ +XMLPUBFUN void XMLCALL + xmlDocDumpFormatMemory (xmlDocPtr cur, + xmlChar **mem, + int *size, + int format); +XMLPUBFUN void XMLCALL + xmlDocDumpMemory (xmlDocPtr cur, + xmlChar **mem, + int *size); +XMLPUBFUN void XMLCALL + xmlDocDumpMemoryEnc (xmlDocPtr out_doc, + xmlChar **doc_txt_ptr, + int * doc_txt_len, + const char *txt_encoding); +XMLPUBFUN void XMLCALL + xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, + xmlChar **doc_txt_ptr, + int * doc_txt_len, + const char *txt_encoding, + int format); +XMLPUBFUN int XMLCALL + xmlDocFormatDump (FILE *f, + xmlDocPtr cur, + int format); +XMLPUBFUN int XMLCALL + xmlDocDump (FILE *f, + xmlDocPtr cur); +XMLPUBFUN void XMLCALL + xmlElemDump (FILE *f, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN int XMLCALL + xmlSaveFile (const char *filename, + xmlDocPtr cur); +XMLPUBFUN int XMLCALL + xmlSaveFormatFile (const char *filename, + xmlDocPtr cur, + int format); +XMLPUBFUN size_t XMLCALL + xmlBufNodeDump (xmlBufPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format); +XMLPUBFUN int XMLCALL + xmlNodeDump (xmlBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format); + +XMLPUBFUN int XMLCALL + xmlSaveFileTo (xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN int XMLCALL + xmlSaveFormatFileTo (xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding, + int format); +XMLPUBFUN void XMLCALL + xmlNodeDumpOutput (xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format, + const char *encoding); + +XMLPUBFUN int XMLCALL + xmlSaveFormatFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding, + int format); + +XMLPUBFUN int XMLCALL + xmlSaveFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding); + +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * XHTML + */ +XMLPUBFUN int XMLCALL + xmlIsXHTML (const xmlChar *systemID, + const xmlChar *publicID); + +/* + * Compression. + */ +XMLPUBFUN int XMLCALL + xmlGetDocCompressMode (const xmlDoc *doc); +XMLPUBFUN void XMLCALL + xmlSetDocCompressMode (xmlDocPtr doc, + int mode); +XMLPUBFUN int XMLCALL + xmlGetCompressMode (void); +XMLPUBFUN void XMLCALL + xmlSetCompressMode (int mode); + +/* +* DOM-wrapper helper functions. +*/ +XMLPUBFUN xmlDOMWrapCtxtPtr XMLCALL + xmlDOMWrapNewCtxt (void); +XMLPUBFUN void XMLCALL + xmlDOMWrapFreeCtxt (xmlDOMWrapCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr elem, + int options); +XMLPUBFUN int XMLCALL + xmlDOMWrapAdoptNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options); +XMLPUBFUN int XMLCALL + xmlDOMWrapRemoveNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr node, + int options); +XMLPUBFUN int XMLCALL + xmlDOMWrapCloneNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlNodePtr *clonedNode, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int deep, + int options); + +#ifdef LIBXML_TREE_ENABLED +/* + * 5 interfaces from DOM ElementTraversal, but different in entities + * traversal. + */ +XMLPUBFUN unsigned long XMLCALL + xmlChildElementCount (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNextElementSibling (xmlNodePtr node); +XMLPUBFUN xmlNodePtr XMLCALL + xmlFirstElementChild (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr XMLCALL + xmlLastElementChild (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr XMLCALL + xmlPreviousElementSibling (xmlNodePtr node); +#endif +#ifdef __cplusplus +} +#endif +#ifndef __XML_PARSER_H__ +#include +#endif + +#endif /* __XML_TREE_H__ */ + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/uri.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/uri.h new file mode 100644 index 0000000..db48262 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/uri.h @@ -0,0 +1,94 @@ +/** + * Summary: library of generic URI related routines + * Description: library of generic URI related routines + * Implements RFC 2396 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_URI_H__ +#define __XML_URI_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlURI: + * + * A parsed URI reference. This is a struct containing the various fields + * as described in RFC 2396 but separated for further processing. + * + * Note: query is a deprecated field which is incorrectly unescaped. + * query_raw takes precedence over query if the former is set. + * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00127 + */ +typedef struct _xmlURI xmlURI; +typedef xmlURI *xmlURIPtr; +struct _xmlURI { + char *scheme; /* the URI scheme */ + char *opaque; /* opaque part */ + char *authority; /* the authority part */ + char *server; /* the server part */ + char *user; /* the user part */ + int port; /* the port number */ + char *path; /* the path string */ + char *query; /* the query string (deprecated - use with caution) */ + char *fragment; /* the fragment identifier */ + int cleanup; /* parsing potentially unclean URI */ + char *query_raw; /* the query string (as it appears in the URI) */ +}; + +/* + * This function is in tree.h: + * xmlChar * xmlNodeGetBase (xmlDocPtr doc, + * xmlNodePtr cur); + */ +XMLPUBFUN xmlURIPtr XMLCALL + xmlCreateURI (void); +XMLPUBFUN xmlChar * XMLCALL + xmlBuildURI (const xmlChar *URI, + const xmlChar *base); +XMLPUBFUN xmlChar * XMLCALL + xmlBuildRelativeURI (const xmlChar *URI, + const xmlChar *base); +XMLPUBFUN xmlURIPtr XMLCALL + xmlParseURI (const char *str); +XMLPUBFUN xmlURIPtr XMLCALL + xmlParseURIRaw (const char *str, + int raw); +XMLPUBFUN int XMLCALL + xmlParseURIReference (xmlURIPtr uri, + const char *str); +XMLPUBFUN xmlChar * XMLCALL + xmlSaveUri (xmlURIPtr uri); +XMLPUBFUN void XMLCALL + xmlPrintURI (FILE *stream, + xmlURIPtr uri); +XMLPUBFUN xmlChar * XMLCALL + xmlURIEscapeStr (const xmlChar *str, + const xmlChar *list); +XMLPUBFUN char * XMLCALL + xmlURIUnescapeString (const char *str, + int len, + char *target); +XMLPUBFUN int XMLCALL + xmlNormalizeURIPath (char *path); +XMLPUBFUN xmlChar * XMLCALL + xmlURIEscape (const xmlChar *str); +XMLPUBFUN void XMLCALL + xmlFreeURI (xmlURIPtr uri); +XMLPUBFUN xmlChar* XMLCALL + xmlCanonicPath (const xmlChar *path); +XMLPUBFUN xmlChar* XMLCALL + xmlPathToURI (const xmlChar *path); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_URI_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/valid.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/valid.h new file mode 100644 index 0000000..2bc7b38 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/valid.h @@ -0,0 +1,458 @@ +/* + * Summary: The DTD validation + * Description: API for the DTD handling and the validity checking + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_VALID_H__ +#define __XML_VALID_H__ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Validation state added for non-determinist content model. + */ +typedef struct _xmlValidState xmlValidState; +typedef xmlValidState *xmlValidStatePtr; + +/** + * xmlValidityErrorFunc: + * @ctx: usually an xmlValidCtxtPtr to a validity error context, + * but comes from ctxt->userData (which normally contains such + * a pointer); ctxt->userData can be changed by the user. + * @msg: the string to format *printf like vararg + * @...: remaining arguments to the format + * + * Callback called when a validity error is found. This is a message + * oriented function similar to an *printf function. + */ +typedef void (XMLCDECL *xmlValidityErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlValidityWarningFunc: + * @ctx: usually an xmlValidCtxtPtr to a validity error context, + * but comes from ctxt->userData (which normally contains such + * a pointer); ctxt->userData can be changed by the user. + * @msg: the string to format *printf like vararg + * @...: remaining arguments to the format + * + * Callback called when a validity warning is found. This is a message + * oriented function similar to an *printf function. + */ +typedef void (XMLCDECL *xmlValidityWarningFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +#ifdef IN_LIBXML +/** + * XML_CTXT_FINISH_DTD_0: + * + * Special value for finishDtd field when embedded in an xmlParserCtxt + */ +#define XML_CTXT_FINISH_DTD_0 0xabcd1234 +/** + * XML_CTXT_FINISH_DTD_1: + * + * Special value for finishDtd field when embedded in an xmlParserCtxt + */ +#define XML_CTXT_FINISH_DTD_1 0xabcd1235 +#endif + +/* + * xmlValidCtxt: + * An xmlValidCtxt is used for error reporting when validating. + */ +typedef struct _xmlValidCtxt xmlValidCtxt; +typedef xmlValidCtxt *xmlValidCtxtPtr; +struct _xmlValidCtxt { + void *userData; /* user specific data block */ + xmlValidityErrorFunc error; /* the callback in case of errors */ + xmlValidityWarningFunc warning; /* the callback in case of warning */ + + /* Node analysis stack used when validating within entities */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + unsigned int finishDtd; /* finished validating the Dtd ? */ + xmlDocPtr doc; /* the document */ + int valid; /* temporary validity check result */ + + /* state state used for non-determinist content validation */ + xmlValidState *vstate; /* current state */ + int vstateNr; /* Depth of the validation stack */ + int vstateMax; /* Max depth of the validation stack */ + xmlValidState *vstateTab; /* array of validation states */ + +#ifdef LIBXML_REGEXP_ENABLED + xmlAutomataPtr am; /* the automata */ + xmlAutomataStatePtr state; /* used to build the automata */ +#else + void *am; + void *state; +#endif +}; + +/* + * ALL notation declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlNotationTable; +typedef xmlNotationTable *xmlNotationTablePtr; + +/* + * ALL element declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlElementTable; +typedef xmlElementTable *xmlElementTablePtr; + +/* + * ALL attribute declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlAttributeTable; +typedef xmlAttributeTable *xmlAttributeTablePtr; + +/* + * ALL IDs attributes are stored in a table. + * There is one table per document. + */ + +typedef struct _xmlHashTable xmlIDTable; +typedef xmlIDTable *xmlIDTablePtr; + +/* + * ALL Refs attributes are stored in a table. + * There is one table per document. + */ + +typedef struct _xmlHashTable xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + +/* Notation */ +XMLPUBFUN xmlNotationPtr XMLCALL + xmlAddNotationDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *PublicID, + const xmlChar *SystemID); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlNotationTablePtr XMLCALL + xmlCopyNotationTable (xmlNotationTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeNotationTable (xmlNotationTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpNotationDecl (xmlBufferPtr buf, + xmlNotationPtr nota); +XMLPUBFUN void XMLCALL + xmlDumpNotationTable (xmlBufferPtr buf, + xmlNotationTablePtr table); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Element Content */ +/* the non Doc version are being deprecated */ +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlNewElementContent (const xmlChar *name, + xmlElementContentType type); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlCopyElementContent (xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + xmlFreeElementContent (xmlElementContentPtr cur); +/* the new versions with doc argument */ +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlNewDocElementContent (xmlDocPtr doc, + const xmlChar *name, + xmlElementContentType type); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlCopyDocElementContent(xmlDocPtr doc, + xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + xmlFreeDocElementContent(xmlDocPtr doc, + xmlElementContentPtr cur); +XMLPUBFUN void XMLCALL + xmlSnprintfElementContent(char *buf, + int size, + xmlElementContentPtr content, + int englob); +#ifdef LIBXML_OUTPUT_ENABLED +/* DEPRECATED */ +XMLPUBFUN void XMLCALL + xmlSprintfElementContent(char *buf, + xmlElementContentPtr content, + int englob); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* DEPRECATED */ + +/* Element */ +XMLPUBFUN xmlElementPtr XMLCALL + xmlAddElementDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *name, + xmlElementTypeVal type, + xmlElementContentPtr content); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlElementTablePtr XMLCALL + xmlCopyElementTable (xmlElementTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeElementTable (xmlElementTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpElementTable (xmlBufferPtr buf, + xmlElementTablePtr table); +XMLPUBFUN void XMLCALL + xmlDumpElementDecl (xmlBufferPtr buf, + xmlElementPtr elem); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Enumeration */ +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlCreateEnumeration (const xmlChar *name); +XMLPUBFUN void XMLCALL + xmlFreeEnumeration (xmlEnumerationPtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlCopyEnumeration (xmlEnumerationPtr cur); +#endif /* LIBXML_TREE_ENABLED */ + +/* Attribute */ +XMLPUBFUN xmlAttributePtr XMLCALL + xmlAddAttributeDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name, + const xmlChar *ns, + xmlAttributeType type, + xmlAttributeDefault def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlAttributeTablePtr XMLCALL + xmlCopyAttributeTable (xmlAttributeTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeAttributeTable (xmlAttributeTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpAttributeTable (xmlBufferPtr buf, + xmlAttributeTablePtr table); +XMLPUBFUN void XMLCALL + xmlDumpAttributeDecl (xmlBufferPtr buf, + xmlAttributePtr attr); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* IDs */ +XMLPUBFUN xmlIDPtr XMLCALL + xmlAddID (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *value, + xmlAttrPtr attr); +XMLPUBFUN void XMLCALL + xmlFreeIDTable (xmlIDTablePtr table); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlGetID (xmlDocPtr doc, + const xmlChar *ID); +XMLPUBFUN int XMLCALL + xmlIsID (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); +XMLPUBFUN int XMLCALL + xmlRemoveID (xmlDocPtr doc, + xmlAttrPtr attr); + +/* IDREFs */ +XMLPUBFUN xmlRefPtr XMLCALL + xmlAddRef (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *value, + xmlAttrPtr attr); +XMLPUBFUN void XMLCALL + xmlFreeRefTable (xmlRefTablePtr table); +XMLPUBFUN int XMLCALL + xmlIsRef (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); +XMLPUBFUN int XMLCALL + xmlRemoveRef (xmlDocPtr doc, + xmlAttrPtr attr); +XMLPUBFUN xmlListPtr XMLCALL + xmlGetRefs (xmlDocPtr doc, + const xmlChar *ID); + +/** + * The public function calls related to validity checking. + */ +#ifdef LIBXML_VALID_ENABLED +/* Allocate/Release Validation Contexts */ +XMLPUBFUN xmlValidCtxtPtr XMLCALL + xmlNewValidCtxt(void); +XMLPUBFUN void XMLCALL + xmlFreeValidCtxt(xmlValidCtxtPtr); + +XMLPUBFUN int XMLCALL + xmlValidateRoot (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlValidateElementDecl (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlElementPtr elem); +XMLPUBFUN xmlChar * XMLCALL + xmlValidNormalizeAttributeValue(xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlChar * XMLCALL + xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlAttributePtr attr); +XMLPUBFUN int XMLCALL + xmlValidateAttributeValue(xmlAttributeType type, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNotationDecl (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNotationPtr nota); +XMLPUBFUN int XMLCALL + xmlValidateDtd (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlDtdPtr dtd); +XMLPUBFUN int XMLCALL + xmlValidateDtdFinal (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlValidateDocument (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlValidateElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlValidateOneElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateOneNamespace (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *prefix, + xmlNsPtr ns, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +#endif /* LIBXML_VALID_ENABLED */ + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int XMLCALL + xmlValidateNotationUse (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *notationName); +#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +XMLPUBFUN int XMLCALL + xmlIsMixedElement (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlAttributePtr XMLCALL + xmlGetDtdAttrDesc (xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name); +XMLPUBFUN xmlAttributePtr XMLCALL + xmlGetDtdQAttrDesc (xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN xmlNotationPtr XMLCALL + xmlGetDtdNotationDesc (xmlDtdPtr dtd, + const xmlChar *name); +XMLPUBFUN xmlElementPtr XMLCALL + xmlGetDtdQElementDesc (xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN xmlElementPtr XMLCALL + xmlGetDtdElementDesc (xmlDtdPtr dtd, + const xmlChar *name); + +#ifdef LIBXML_VALID_ENABLED + +XMLPUBFUN int XMLCALL + xmlValidGetPotentialChildren(xmlElementContent *ctree, + const xmlChar **names, + int *len, + int max); + +XMLPUBFUN int XMLCALL + xmlValidGetValidElements(xmlNode *prev, + xmlNode *next, + const xmlChar **names, + int max); +XMLPUBFUN int XMLCALL + xmlValidateNameValue (const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNamesValue (const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNmtokenValue (const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNmtokensValue(const xmlChar *value); + +#ifdef LIBXML_REGEXP_ENABLED +/* + * Validation based on the regexp support + */ +XMLPUBFUN int XMLCALL + xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, + xmlElementPtr elem); + +XMLPUBFUN int XMLCALL + xmlValidatePushElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *qname); +XMLPUBFUN int XMLCALL + xmlValidatePushCData (xmlValidCtxtPtr ctxt, + const xmlChar *data, + int len); +XMLPUBFUN int XMLCALL + xmlValidatePopElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *qname); +#endif /* LIBXML_REGEXP_ENABLED */ +#endif /* LIBXML_VALID_ENABLED */ +#ifdef __cplusplus +} +#endif +#endif /* __XML_VALID_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xinclude.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xinclude.h new file mode 100644 index 0000000..863ab25 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xinclude.h @@ -0,0 +1,129 @@ +/* + * Summary: implementation of XInclude + * Description: API to handle XInclude processing, + * implements the + * World Wide Web Consortium Last Call Working Draft 10 November 2003 + * http://www.w3.org/TR/2003/WD-xinclude-20031110 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XINCLUDE_H__ +#define __XML_XINCLUDE_H__ + +#include +#include + +#ifdef LIBXML_XINCLUDE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XINCLUDE_NS: + * + * Macro defining the Xinclude namespace: http://www.w3.org/2003/XInclude + */ +#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2003/XInclude" +/** + * XINCLUDE_OLD_NS: + * + * Macro defining the draft Xinclude namespace: http://www.w3.org/2001/XInclude + */ +#define XINCLUDE_OLD_NS (const xmlChar *) "http://www.w3.org/2001/XInclude" +/** + * XINCLUDE_NODE: + * + * Macro defining "include" + */ +#define XINCLUDE_NODE (const xmlChar *) "include" +/** + * XINCLUDE_FALLBACK: + * + * Macro defining "fallback" + */ +#define XINCLUDE_FALLBACK (const xmlChar *) "fallback" +/** + * XINCLUDE_HREF: + * + * Macro defining "href" + */ +#define XINCLUDE_HREF (const xmlChar *) "href" +/** + * XINCLUDE_PARSE: + * + * Macro defining "parse" + */ +#define XINCLUDE_PARSE (const xmlChar *) "parse" +/** + * XINCLUDE_PARSE_XML: + * + * Macro defining "xml" + */ +#define XINCLUDE_PARSE_XML (const xmlChar *) "xml" +/** + * XINCLUDE_PARSE_TEXT: + * + * Macro defining "text" + */ +#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text" +/** + * XINCLUDE_PARSE_ENCODING: + * + * Macro defining "encoding" + */ +#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding" +/** + * XINCLUDE_PARSE_XPOINTER: + * + * Macro defining "xpointer" + */ +#define XINCLUDE_PARSE_XPOINTER (const xmlChar *) "xpointer" + +typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt; +typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr; + +/* + * standalone processing + */ +XMLPUBFUN int XMLCALL + xmlXIncludeProcess (xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessFlags (xmlDocPtr doc, + int flags); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessFlagsData(xmlDocPtr doc, + int flags, + void *data); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, + int flags, + void *data); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessTree (xmlNodePtr tree); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessTreeFlags(xmlNodePtr tree, + int flags); +/* + * contextual processing + */ +XMLPUBFUN xmlXIncludeCtxtPtr XMLCALL + xmlXIncludeNewContext (xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt, + int flags); +XMLPUBFUN void XMLCALL + xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessNode (xmlXIncludeCtxtPtr ctxt, + xmlNodePtr tree); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XINCLUDE_ENABLED */ + +#endif /* __XML_XINCLUDE_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xlink.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xlink.h new file mode 100644 index 0000000..a209a99 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xlink.h @@ -0,0 +1,189 @@ +/* + * Summary: unfinished XLink detection module + * Description: unfinished XLink detection module + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XLINK_H__ +#define __XML_XLINK_H__ + +#include +#include + +#ifdef LIBXML_XPTR_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Various defines for the various Link properties. + * + * NOTE: the link detection layer will try to resolve QName expansion + * of namespaces. If "foo" is the prefix for "http://foo.com/" + * then the link detection layer will expand role="foo:myrole" + * to "http://foo.com/:myrole". + * NOTE: the link detection layer will expand URI-Refences found on + * href attributes by using the base mechanism if found. + */ +typedef xmlChar *xlinkHRef; +typedef xmlChar *xlinkRole; +typedef xmlChar *xlinkTitle; + +typedef enum { + XLINK_TYPE_NONE = 0, + XLINK_TYPE_SIMPLE, + XLINK_TYPE_EXTENDED, + XLINK_TYPE_EXTENDED_SET +} xlinkType; + +typedef enum { + XLINK_SHOW_NONE = 0, + XLINK_SHOW_NEW, + XLINK_SHOW_EMBED, + XLINK_SHOW_REPLACE +} xlinkShow; + +typedef enum { + XLINK_ACTUATE_NONE = 0, + XLINK_ACTUATE_AUTO, + XLINK_ACTUATE_ONREQUEST +} xlinkActuate; + +/** + * xlinkNodeDetectFunc: + * @ctx: user data pointer + * @node: the node to check + * + * This is the prototype for the link detection routine. + * It calls the default link detection callbacks upon link detection. + */ +typedef void (*xlinkNodeDetectFunc) (void *ctx, xmlNodePtr node); + +/* + * The link detection module interact with the upper layers using + * a set of callback registered at parsing time. + */ + +/** + * xlinkSimpleLinkFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @href: the target of the link + * @role: the role string + * @title: the link title + * + * This is the prototype for a simple link detection callback. + */ +typedef void +(*xlinkSimpleLinkFunk) (void *ctx, + xmlNodePtr node, + const xlinkHRef href, + const xlinkRole role, + const xlinkTitle title); + +/** + * xlinkExtendedLinkFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @nbLocators: the number of locators detected on the link + * @hrefs: pointer to the array of locator hrefs + * @roles: pointer to the array of locator roles + * @nbArcs: the number of arcs detected on the link + * @from: pointer to the array of source roles found on the arcs + * @to: pointer to the array of target roles found on the arcs + * @show: array of values for the show attributes found on the arcs + * @actuate: array of values for the actuate attributes found on the arcs + * @nbTitles: the number of titles detected on the link + * @title: array of titles detected on the link + * @langs: array of xml:lang values for the titles + * + * This is the prototype for a extended link detection callback. + */ +typedef void +(*xlinkExtendedLinkFunk)(void *ctx, + xmlNodePtr node, + int nbLocators, + const xlinkHRef *hrefs, + const xlinkRole *roles, + int nbArcs, + const xlinkRole *from, + const xlinkRole *to, + xlinkShow *show, + xlinkActuate *actuate, + int nbTitles, + const xlinkTitle *titles, + const xmlChar **langs); + +/** + * xlinkExtendedLinkSetFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @nbLocators: the number of locators detected on the link + * @hrefs: pointer to the array of locator hrefs + * @roles: pointer to the array of locator roles + * @nbTitles: the number of titles detected on the link + * @title: array of titles detected on the link + * @langs: array of xml:lang values for the titles + * + * This is the prototype for a extended link set detection callback. + */ +typedef void +(*xlinkExtendedLinkSetFunk) (void *ctx, + xmlNodePtr node, + int nbLocators, + const xlinkHRef *hrefs, + const xlinkRole *roles, + int nbTitles, + const xlinkTitle *titles, + const xmlChar **langs); + +/** + * This is the structure containing a set of Links detection callbacks. + * + * There is no default xlink callbacks, if one want to get link + * recognition activated, those call backs must be provided before parsing. + */ +typedef struct _xlinkHandler xlinkHandler; +typedef xlinkHandler *xlinkHandlerPtr; +struct _xlinkHandler { + xlinkSimpleLinkFunk simple; + xlinkExtendedLinkFunk extended; + xlinkExtendedLinkSetFunk set; +}; + +/* + * The default detection routine, can be overridden, they call the default + * detection callbacks. + */ + +XMLPUBFUN xlinkNodeDetectFunc XMLCALL + xlinkGetDefaultDetect (void); +XMLPUBFUN void XMLCALL + xlinkSetDefaultDetect (xlinkNodeDetectFunc func); + +/* + * Routines to set/get the default handlers. + */ +XMLPUBFUN xlinkHandlerPtr XMLCALL + xlinkGetDefaultHandler (void); +XMLPUBFUN void XMLCALL + xlinkSetDefaultHandler (xlinkHandlerPtr handler); + +/* + * Link detection module itself. + */ +XMLPUBFUN xlinkType XMLCALL + xlinkIsLink (xmlDocPtr doc, + xmlNodePtr node); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPTR_ENABLED */ + +#endif /* __XML_XLINK_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlIO.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlIO.h new file mode 100644 index 0000000..3e41744 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlIO.h @@ -0,0 +1,366 @@ +/* + * Summary: interface for the I/O interfaces used by the parser + * Description: interface for the I/O interfaces used by the parser + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_IO_H__ +#define __XML_IO_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Those are the functions and datatypes for the parser input + * I/O structures. + */ + +/** + * xmlInputMatchCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Input API to detect if the current handler + * can provide input fonctionnalities for this resource. + * + * Returns 1 if yes and 0 if another Input module should be used + */ +typedef int (XMLCALL *xmlInputMatchCallback) (char const *filename); +/** + * xmlInputOpenCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Input API to open the resource + * + * Returns an Input context or NULL in case or error + */ +typedef void * (XMLCALL *xmlInputOpenCallback) (char const *filename); +/** + * xmlInputReadCallback: + * @context: an Input context + * @buffer: the buffer to store data read + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Input API to read the resource + * + * Returns the number of bytes read or -1 in case of error + */ +typedef int (XMLCALL *xmlInputReadCallback) (void * context, char * buffer, int len); +/** + * xmlInputCloseCallback: + * @context: an Input context + * + * Callback used in the I/O Input API to close the resource + * + * Returns 0 or -1 in case of error + */ +typedef int (XMLCALL *xmlInputCloseCallback) (void * context); + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Those are the functions and datatypes for the library output + * I/O structures. + */ + +/** + * xmlOutputMatchCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Output API to detect if the current handler + * can provide output fonctionnalities for this resource. + * + * Returns 1 if yes and 0 if another Output module should be used + */ +typedef int (XMLCALL *xmlOutputMatchCallback) (char const *filename); +/** + * xmlOutputOpenCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Output API to open the resource + * + * Returns an Output context or NULL in case or error + */ +typedef void * (XMLCALL *xmlOutputOpenCallback) (char const *filename); +/** + * xmlOutputWriteCallback: + * @context: an Output context + * @buffer: the buffer of data to write + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Output API to write to the resource + * + * Returns the number of bytes written or -1 in case of error + */ +typedef int (XMLCALL *xmlOutputWriteCallback) (void * context, const char * buffer, + int len); +/** + * xmlOutputCloseCallback: + * @context: an Output context + * + * Callback used in the I/O Output API to close the resource + * + * Returns 0 or -1 in case of error + */ +typedef int (XMLCALL *xmlOutputCloseCallback) (void * context); +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +struct _xmlParserInputBuffer { + void* context; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufPtr buffer; /* Local buffer encoded in UTF-8 */ + xmlBufPtr raw; /* if encoder != NULL buffer for raw input */ + int compressed; /* -1=unknown, 0=not compressed, 1=compressed */ + int error; + unsigned long rawconsumed;/* amount consumed from raw */ +}; + + +#ifdef LIBXML_OUTPUT_ENABLED +struct _xmlOutputBuffer { + void* context; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ + xmlBufPtr conv; /* if encoder != NULL buffer for output */ + int written; /* total number of byte written */ + int error; +}; +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* + * Interfaces for input + */ +XMLPUBFUN void XMLCALL + xmlCleanupInputCallbacks (void); + +XMLPUBFUN int XMLCALL + xmlPopInputCallbacks (void); + +XMLPUBFUN void XMLCALL + xmlRegisterDefaultInputCallbacks (void); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlAllocParserInputBuffer (xmlCharEncoding enc); + +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateFilename (const char *URI, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateFile (FILE *file, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateFd (int fd, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateMem (const char *mem, int size, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateStatic (const char *mem, int size, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + xmlParserInputBufferRead (xmlParserInputBufferPtr in, + int len); +XMLPUBFUN int XMLCALL + xmlParserInputBufferGrow (xmlParserInputBufferPtr in, + int len); +XMLPUBFUN int XMLCALL + xmlParserInputBufferPush (xmlParserInputBufferPtr in, + int len, + const char *buf); +XMLPUBFUN void XMLCALL + xmlFreeParserInputBuffer (xmlParserInputBufferPtr in); +XMLPUBFUN char * XMLCALL + xmlParserGetDirectory (const char *filename); + +XMLPUBFUN int XMLCALL + xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, + xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc); + +xmlParserInputBufferPtr + __xmlParserInputBufferCreateFilename(const char *URI, + xmlCharEncoding enc); + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Interfaces for output + */ +XMLPUBFUN void XMLCALL + xmlCleanupOutputCallbacks (void); +XMLPUBFUN void XMLCALL + xmlRegisterDefaultOutputCallbacks(void); +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlAllocOutputBuffer (xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateFilename (const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateFile (FILE *file, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateBuffer (xmlBufferPtr buffer, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateFd (int fd, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + xmlCharEncodingHandlerPtr encoder); + +/* Couple of APIs to get the output without digging into the buffers */ +XMLPUBFUN const xmlChar * XMLCALL + xmlOutputBufferGetContent (xmlOutputBufferPtr out); +XMLPUBFUN size_t XMLCALL + xmlOutputBufferGetSize (xmlOutputBufferPtr out); + +XMLPUBFUN int XMLCALL + xmlOutputBufferWrite (xmlOutputBufferPtr out, + int len, + const char *buf); +XMLPUBFUN int XMLCALL + xmlOutputBufferWriteString (xmlOutputBufferPtr out, + const char *str); +XMLPUBFUN int XMLCALL + xmlOutputBufferWriteEscape (xmlOutputBufferPtr out, + const xmlChar *str, + xmlCharEncodingOutputFunc escaping); + +XMLPUBFUN int XMLCALL + xmlOutputBufferFlush (xmlOutputBufferPtr out); +XMLPUBFUN int XMLCALL + xmlOutputBufferClose (xmlOutputBufferPtr out); + +XMLPUBFUN int XMLCALL + xmlRegisterOutputCallbacks (xmlOutputMatchCallback matchFunc, + xmlOutputOpenCallback openFunc, + xmlOutputWriteCallback writeFunc, + xmlOutputCloseCallback closeFunc); + +xmlOutputBufferPtr + __xmlOutputBufferCreateFilename(const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +#ifdef LIBXML_HTTP_ENABLED +/* This function only exists if HTTP support built into the library */ +XMLPUBFUN void XMLCALL + xmlRegisterHTTPPostCallbacks (void ); +#endif /* LIBXML_HTTP_ENABLED */ + +#endif /* LIBXML_OUTPUT_ENABLED */ + +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlCheckHTTPInput (xmlParserCtxtPtr ctxt, + xmlParserInputPtr ret); + +/* + * A predefined entity loader disabling network accesses + */ +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNoNetExternalEntityLoader (const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + +/* + * xmlNormalizeWindowsPath is obsolete, don't use it. + * Check xmlCanonicPath in uri.h for a better alternative. + */ +XMLPUBFUN xmlChar * XMLCALL + xmlNormalizeWindowsPath (const xmlChar *path); + +XMLPUBFUN int XMLCALL + xmlCheckFilename (const char *path); +/** + * Default 'file://' protocol callbacks + */ +XMLPUBFUN int XMLCALL + xmlFileMatch (const char *filename); +XMLPUBFUN void * XMLCALL + xmlFileOpen (const char *filename); +XMLPUBFUN int XMLCALL + xmlFileRead (void * context, + char * buffer, + int len); +XMLPUBFUN int XMLCALL + xmlFileClose (void * context); + +/** + * Default 'http://' protocol callbacks + */ +#ifdef LIBXML_HTTP_ENABLED +XMLPUBFUN int XMLCALL + xmlIOHTTPMatch (const char *filename); +XMLPUBFUN void * XMLCALL + xmlIOHTTPOpen (const char *filename); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void * XMLCALL + xmlIOHTTPOpenW (const char * post_uri, + int compression ); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN int XMLCALL + xmlIOHTTPRead (void * context, + char * buffer, + int len); +XMLPUBFUN int XMLCALL + xmlIOHTTPClose (void * context); +#endif /* LIBXML_HTTP_ENABLED */ + +/** + * Default 'ftp://' protocol callbacks + */ +#ifdef LIBXML_FTP_ENABLED +XMLPUBFUN int XMLCALL + xmlIOFTPMatch (const char *filename); +XMLPUBFUN void * XMLCALL + xmlIOFTPOpen (const char *filename); +XMLPUBFUN int XMLCALL + xmlIOFTPRead (void * context, + char * buffer, + int len); +XMLPUBFUN int XMLCALL + xmlIOFTPClose (void * context); +#endif /* LIBXML_FTP_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_IO_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlautomata.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlautomata.h new file mode 100644 index 0000000..bf1b131 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlautomata.h @@ -0,0 +1,146 @@ +/* + * Summary: API to build regexp automata + * Description: the API to build regexp automata + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_AUTOMATA_H__ +#define __XML_AUTOMATA_H__ + +#include +#include + +#ifdef LIBXML_REGEXP_ENABLED +#ifdef LIBXML_AUTOMATA_ENABLED +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlAutomataPtr: + * + * A libxml automata description, It can be compiled into a regexp + */ +typedef struct _xmlAutomata xmlAutomata; +typedef xmlAutomata *xmlAutomataPtr; + +/** + * xmlAutomataStatePtr: + * + * A state int the automata description, + */ +typedef struct _xmlAutomataState xmlAutomataState; +typedef xmlAutomataState *xmlAutomataStatePtr; + +/* + * Building API + */ +XMLPUBFUN xmlAutomataPtr XMLCALL + xmlNewAutomata (void); +XMLPUBFUN void XMLCALL + xmlFreeAutomata (xmlAutomataPtr am); + +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataGetInitState (xmlAutomataPtr am); +XMLPUBFUN int XMLCALL + xmlAutomataSetFinalState (xmlAutomataPtr am, + xmlAutomataStatePtr state); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewState (xmlAutomataPtr am); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewTransition (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewTransition2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewNegTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + void *data); + +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCountTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCountTrans2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewOnceTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewOnceTrans2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewAllTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int lax); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewEpsilon (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCountedTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int counter); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCounterTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int counter); +XMLPUBFUN int XMLCALL + xmlAutomataNewCounter (xmlAutomataPtr am, + int min, + int max); + +XMLPUBFUN xmlRegexpPtr XMLCALL + xmlAutomataCompile (xmlAutomataPtr am); +XMLPUBFUN int XMLCALL + xmlAutomataIsDeterminist (xmlAutomataPtr am); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_AUTOMATA_ENABLED */ +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /* __XML_AUTOMATA_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlerror.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlerror.h new file mode 100644 index 0000000..43e68ca --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlerror.h @@ -0,0 +1,945 @@ +/* + * Summary: error handling + * Description: the API used to report errors + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#include + +#ifndef __XML_ERROR_H__ +#define __XML_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlErrorLevel: + * + * Indicates the level of an error + */ +typedef enum { + XML_ERR_NONE = 0, + XML_ERR_WARNING = 1, /* A simple warning */ + XML_ERR_ERROR = 2, /* A recoverable error */ + XML_ERR_FATAL = 3 /* A fatal error */ +} xmlErrorLevel; + +/** + * xmlErrorDomain: + * + * Indicates where an error may have come from + */ +typedef enum { + XML_FROM_NONE = 0, + XML_FROM_PARSER, /* The XML parser */ + XML_FROM_TREE, /* The tree module */ + XML_FROM_NAMESPACE, /* The XML Namespace module */ + XML_FROM_DTD, /* The XML DTD validation with parser context*/ + XML_FROM_HTML, /* The HTML parser */ + XML_FROM_MEMORY, /* The memory allocator */ + XML_FROM_OUTPUT, /* The serialization code */ + XML_FROM_IO, /* The Input/Output stack */ + XML_FROM_FTP, /* The FTP module */ + XML_FROM_HTTP, /* The HTTP module */ + XML_FROM_XINCLUDE, /* The XInclude processing */ + XML_FROM_XPATH, /* The XPath module */ + XML_FROM_XPOINTER, /* The XPointer module */ + XML_FROM_REGEXP, /* The regular expressions module */ + XML_FROM_DATATYPE, /* The W3C XML Schemas Datatype module */ + XML_FROM_SCHEMASP, /* The W3C XML Schemas parser module */ + XML_FROM_SCHEMASV, /* The W3C XML Schemas validation module */ + XML_FROM_RELAXNGP, /* The Relax-NG parser module */ + XML_FROM_RELAXNGV, /* The Relax-NG validator module */ + XML_FROM_CATALOG, /* The Catalog module */ + XML_FROM_C14N, /* The Canonicalization module */ + XML_FROM_XSLT, /* The XSLT engine from libxslt */ + XML_FROM_VALID, /* The XML DTD validation with valid context */ + XML_FROM_CHECK, /* The error checking module */ + XML_FROM_WRITER, /* The xmlwriter module */ + XML_FROM_MODULE, /* The dynamically loaded module module*/ + XML_FROM_I18N, /* The module handling character conversion */ + XML_FROM_SCHEMATRONV,/* The Schematron validator module */ + XML_FROM_BUFFER, /* The buffers module */ + XML_FROM_URI /* The URI module */ +} xmlErrorDomain; + +/** + * xmlError: + * + * An XML Error instance. + */ + +typedef struct _xmlError xmlError; +typedef xmlError *xmlErrorPtr; +struct _xmlError { + int domain; /* What part of the library raised this error */ + int code; /* The error code, e.g. an xmlParserError */ + char *message;/* human-readable informative error message */ + xmlErrorLevel level;/* how consequent is the error */ + char *file; /* the filename */ + int line; /* the line number if available */ + char *str1; /* extra string information */ + char *str2; /* extra string information */ + char *str3; /* extra string information */ + int int1; /* extra number information */ + int int2; /* error column # or 0 if N/A (todo: rename field when we would brk ABI) */ + void *ctxt; /* the parser context if available */ + void *node; /* the node in the tree */ +}; + +/** + * xmlParserError: + * + * This is an error that the XML (or HTML) parser can generate + */ +typedef enum { + XML_ERR_OK = 0, + XML_ERR_INTERNAL_ERROR, /* 1 */ + XML_ERR_NO_MEMORY, /* 2 */ + XML_ERR_DOCUMENT_START, /* 3 */ + XML_ERR_DOCUMENT_EMPTY, /* 4 */ + XML_ERR_DOCUMENT_END, /* 5 */ + XML_ERR_INVALID_HEX_CHARREF, /* 6 */ + XML_ERR_INVALID_DEC_CHARREF, /* 7 */ + XML_ERR_INVALID_CHARREF, /* 8 */ + XML_ERR_INVALID_CHAR, /* 9 */ + XML_ERR_CHARREF_AT_EOF, /* 10 */ + XML_ERR_CHARREF_IN_PROLOG, /* 11 */ + XML_ERR_CHARREF_IN_EPILOG, /* 12 */ + XML_ERR_CHARREF_IN_DTD, /* 13 */ + XML_ERR_ENTITYREF_AT_EOF, /* 14 */ + XML_ERR_ENTITYREF_IN_PROLOG, /* 15 */ + XML_ERR_ENTITYREF_IN_EPILOG, /* 16 */ + XML_ERR_ENTITYREF_IN_DTD, /* 17 */ + XML_ERR_PEREF_AT_EOF, /* 18 */ + XML_ERR_PEREF_IN_PROLOG, /* 19 */ + XML_ERR_PEREF_IN_EPILOG, /* 20 */ + XML_ERR_PEREF_IN_INT_SUBSET, /* 21 */ + XML_ERR_ENTITYREF_NO_NAME, /* 22 */ + XML_ERR_ENTITYREF_SEMICOL_MISSING, /* 23 */ + XML_ERR_PEREF_NO_NAME, /* 24 */ + XML_ERR_PEREF_SEMICOL_MISSING, /* 25 */ + XML_ERR_UNDECLARED_ENTITY, /* 26 */ + XML_WAR_UNDECLARED_ENTITY, /* 27 */ + XML_ERR_UNPARSED_ENTITY, /* 28 */ + XML_ERR_ENTITY_IS_EXTERNAL, /* 29 */ + XML_ERR_ENTITY_IS_PARAMETER, /* 30 */ + XML_ERR_UNKNOWN_ENCODING, /* 31 */ + XML_ERR_UNSUPPORTED_ENCODING, /* 32 */ + XML_ERR_STRING_NOT_STARTED, /* 33 */ + XML_ERR_STRING_NOT_CLOSED, /* 34 */ + XML_ERR_NS_DECL_ERROR, /* 35 */ + XML_ERR_ENTITY_NOT_STARTED, /* 36 */ + XML_ERR_ENTITY_NOT_FINISHED, /* 37 */ + XML_ERR_LT_IN_ATTRIBUTE, /* 38 */ + XML_ERR_ATTRIBUTE_NOT_STARTED, /* 39 */ + XML_ERR_ATTRIBUTE_NOT_FINISHED, /* 40 */ + XML_ERR_ATTRIBUTE_WITHOUT_VALUE, /* 41 */ + XML_ERR_ATTRIBUTE_REDEFINED, /* 42 */ + XML_ERR_LITERAL_NOT_STARTED, /* 43 */ + XML_ERR_LITERAL_NOT_FINISHED, /* 44 */ + XML_ERR_COMMENT_NOT_FINISHED, /* 45 */ + XML_ERR_PI_NOT_STARTED, /* 46 */ + XML_ERR_PI_NOT_FINISHED, /* 47 */ + XML_ERR_NOTATION_NOT_STARTED, /* 48 */ + XML_ERR_NOTATION_NOT_FINISHED, /* 49 */ + XML_ERR_ATTLIST_NOT_STARTED, /* 50 */ + XML_ERR_ATTLIST_NOT_FINISHED, /* 51 */ + XML_ERR_MIXED_NOT_STARTED, /* 52 */ + XML_ERR_MIXED_NOT_FINISHED, /* 53 */ + XML_ERR_ELEMCONTENT_NOT_STARTED, /* 54 */ + XML_ERR_ELEMCONTENT_NOT_FINISHED, /* 55 */ + XML_ERR_XMLDECL_NOT_STARTED, /* 56 */ + XML_ERR_XMLDECL_NOT_FINISHED, /* 57 */ + XML_ERR_CONDSEC_NOT_STARTED, /* 58 */ + XML_ERR_CONDSEC_NOT_FINISHED, /* 59 */ + XML_ERR_EXT_SUBSET_NOT_FINISHED, /* 60 */ + XML_ERR_DOCTYPE_NOT_FINISHED, /* 61 */ + XML_ERR_MISPLACED_CDATA_END, /* 62 */ + XML_ERR_CDATA_NOT_FINISHED, /* 63 */ + XML_ERR_RESERVED_XML_NAME, /* 64 */ + XML_ERR_SPACE_REQUIRED, /* 65 */ + XML_ERR_SEPARATOR_REQUIRED, /* 66 */ + XML_ERR_NMTOKEN_REQUIRED, /* 67 */ + XML_ERR_NAME_REQUIRED, /* 68 */ + XML_ERR_PCDATA_REQUIRED, /* 69 */ + XML_ERR_URI_REQUIRED, /* 70 */ + XML_ERR_PUBID_REQUIRED, /* 71 */ + XML_ERR_LT_REQUIRED, /* 72 */ + XML_ERR_GT_REQUIRED, /* 73 */ + XML_ERR_LTSLASH_REQUIRED, /* 74 */ + XML_ERR_EQUAL_REQUIRED, /* 75 */ + XML_ERR_TAG_NAME_MISMATCH, /* 76 */ + XML_ERR_TAG_NOT_FINISHED, /* 77 */ + XML_ERR_STANDALONE_VALUE, /* 78 */ + XML_ERR_ENCODING_NAME, /* 79 */ + XML_ERR_HYPHEN_IN_COMMENT, /* 80 */ + XML_ERR_INVALID_ENCODING, /* 81 */ + XML_ERR_EXT_ENTITY_STANDALONE, /* 82 */ + XML_ERR_CONDSEC_INVALID, /* 83 */ + XML_ERR_VALUE_REQUIRED, /* 84 */ + XML_ERR_NOT_WELL_BALANCED, /* 85 */ + XML_ERR_EXTRA_CONTENT, /* 86 */ + XML_ERR_ENTITY_CHAR_ERROR, /* 87 */ + XML_ERR_ENTITY_PE_INTERNAL, /* 88 */ + XML_ERR_ENTITY_LOOP, /* 89 */ + XML_ERR_ENTITY_BOUNDARY, /* 90 */ + XML_ERR_INVALID_URI, /* 91 */ + XML_ERR_URI_FRAGMENT, /* 92 */ + XML_WAR_CATALOG_PI, /* 93 */ + XML_ERR_NO_DTD, /* 94 */ + XML_ERR_CONDSEC_INVALID_KEYWORD, /* 95 */ + XML_ERR_VERSION_MISSING, /* 96 */ + XML_WAR_UNKNOWN_VERSION, /* 97 */ + XML_WAR_LANG_VALUE, /* 98 */ + XML_WAR_NS_URI, /* 99 */ + XML_WAR_NS_URI_RELATIVE, /* 100 */ + XML_ERR_MISSING_ENCODING, /* 101 */ + XML_WAR_SPACE_VALUE, /* 102 */ + XML_ERR_NOT_STANDALONE, /* 103 */ + XML_ERR_ENTITY_PROCESSING, /* 104 */ + XML_ERR_NOTATION_PROCESSING, /* 105 */ + XML_WAR_NS_COLUMN, /* 106 */ + XML_WAR_ENTITY_REDEFINED, /* 107 */ + XML_ERR_UNKNOWN_VERSION, /* 108 */ + XML_ERR_VERSION_MISMATCH, /* 109 */ + XML_ERR_NAME_TOO_LONG, /* 110 */ + XML_ERR_USER_STOP, /* 111 */ + XML_NS_ERR_XML_NAMESPACE = 200, + XML_NS_ERR_UNDEFINED_NAMESPACE, /* 201 */ + XML_NS_ERR_QNAME, /* 202 */ + XML_NS_ERR_ATTRIBUTE_REDEFINED, /* 203 */ + XML_NS_ERR_EMPTY, /* 204 */ + XML_NS_ERR_COLON, /* 205 */ + XML_DTD_ATTRIBUTE_DEFAULT = 500, + XML_DTD_ATTRIBUTE_REDEFINED, /* 501 */ + XML_DTD_ATTRIBUTE_VALUE, /* 502 */ + XML_DTD_CONTENT_ERROR, /* 503 */ + XML_DTD_CONTENT_MODEL, /* 504 */ + XML_DTD_CONTENT_NOT_DETERMINIST, /* 505 */ + XML_DTD_DIFFERENT_PREFIX, /* 506 */ + XML_DTD_ELEM_DEFAULT_NAMESPACE, /* 507 */ + XML_DTD_ELEM_NAMESPACE, /* 508 */ + XML_DTD_ELEM_REDEFINED, /* 509 */ + XML_DTD_EMPTY_NOTATION, /* 510 */ + XML_DTD_ENTITY_TYPE, /* 511 */ + XML_DTD_ID_FIXED, /* 512 */ + XML_DTD_ID_REDEFINED, /* 513 */ + XML_DTD_ID_SUBSET, /* 514 */ + XML_DTD_INVALID_CHILD, /* 515 */ + XML_DTD_INVALID_DEFAULT, /* 516 */ + XML_DTD_LOAD_ERROR, /* 517 */ + XML_DTD_MISSING_ATTRIBUTE, /* 518 */ + XML_DTD_MIXED_CORRUPT, /* 519 */ + XML_DTD_MULTIPLE_ID, /* 520 */ + XML_DTD_NO_DOC, /* 521 */ + XML_DTD_NO_DTD, /* 522 */ + XML_DTD_NO_ELEM_NAME, /* 523 */ + XML_DTD_NO_PREFIX, /* 524 */ + XML_DTD_NO_ROOT, /* 525 */ + XML_DTD_NOTATION_REDEFINED, /* 526 */ + XML_DTD_NOTATION_VALUE, /* 527 */ + XML_DTD_NOT_EMPTY, /* 528 */ + XML_DTD_NOT_PCDATA, /* 529 */ + XML_DTD_NOT_STANDALONE, /* 530 */ + XML_DTD_ROOT_NAME, /* 531 */ + XML_DTD_STANDALONE_WHITE_SPACE, /* 532 */ + XML_DTD_UNKNOWN_ATTRIBUTE, /* 533 */ + XML_DTD_UNKNOWN_ELEM, /* 534 */ + XML_DTD_UNKNOWN_ENTITY, /* 535 */ + XML_DTD_UNKNOWN_ID, /* 536 */ + XML_DTD_UNKNOWN_NOTATION, /* 537 */ + XML_DTD_STANDALONE_DEFAULTED, /* 538 */ + XML_DTD_XMLID_VALUE, /* 539 */ + XML_DTD_XMLID_TYPE, /* 540 */ + XML_DTD_DUP_TOKEN, /* 541 */ + XML_HTML_STRUCURE_ERROR = 800, + XML_HTML_UNKNOWN_TAG, /* 801 */ + XML_RNGP_ANYNAME_ATTR_ANCESTOR = 1000, + XML_RNGP_ATTR_CONFLICT, /* 1001 */ + XML_RNGP_ATTRIBUTE_CHILDREN, /* 1002 */ + XML_RNGP_ATTRIBUTE_CONTENT, /* 1003 */ + XML_RNGP_ATTRIBUTE_EMPTY, /* 1004 */ + XML_RNGP_ATTRIBUTE_NOOP, /* 1005 */ + XML_RNGP_CHOICE_CONTENT, /* 1006 */ + XML_RNGP_CHOICE_EMPTY, /* 1007 */ + XML_RNGP_CREATE_FAILURE, /* 1008 */ + XML_RNGP_DATA_CONTENT, /* 1009 */ + XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, /* 1010 */ + XML_RNGP_DEFINE_CREATE_FAILED, /* 1011 */ + XML_RNGP_DEFINE_EMPTY, /* 1012 */ + XML_RNGP_DEFINE_MISSING, /* 1013 */ + XML_RNGP_DEFINE_NAME_MISSING, /* 1014 */ + XML_RNGP_ELEM_CONTENT_EMPTY, /* 1015 */ + XML_RNGP_ELEM_CONTENT_ERROR, /* 1016 */ + XML_RNGP_ELEMENT_EMPTY, /* 1017 */ + XML_RNGP_ELEMENT_CONTENT, /* 1018 */ + XML_RNGP_ELEMENT_NAME, /* 1019 */ + XML_RNGP_ELEMENT_NO_CONTENT, /* 1020 */ + XML_RNGP_ELEM_TEXT_CONFLICT, /* 1021 */ + XML_RNGP_EMPTY, /* 1022 */ + XML_RNGP_EMPTY_CONSTRUCT, /* 1023 */ + XML_RNGP_EMPTY_CONTENT, /* 1024 */ + XML_RNGP_EMPTY_NOT_EMPTY, /* 1025 */ + XML_RNGP_ERROR_TYPE_LIB, /* 1026 */ + XML_RNGP_EXCEPT_EMPTY, /* 1027 */ + XML_RNGP_EXCEPT_MISSING, /* 1028 */ + XML_RNGP_EXCEPT_MULTIPLE, /* 1029 */ + XML_RNGP_EXCEPT_NO_CONTENT, /* 1030 */ + XML_RNGP_EXTERNALREF_EMTPY, /* 1031 */ + XML_RNGP_EXTERNAL_REF_FAILURE, /* 1032 */ + XML_RNGP_EXTERNALREF_RECURSE, /* 1033 */ + XML_RNGP_FORBIDDEN_ATTRIBUTE, /* 1034 */ + XML_RNGP_FOREIGN_ELEMENT, /* 1035 */ + XML_RNGP_GRAMMAR_CONTENT, /* 1036 */ + XML_RNGP_GRAMMAR_EMPTY, /* 1037 */ + XML_RNGP_GRAMMAR_MISSING, /* 1038 */ + XML_RNGP_GRAMMAR_NO_START, /* 1039 */ + XML_RNGP_GROUP_ATTR_CONFLICT, /* 1040 */ + XML_RNGP_HREF_ERROR, /* 1041 */ + XML_RNGP_INCLUDE_EMPTY, /* 1042 */ + XML_RNGP_INCLUDE_FAILURE, /* 1043 */ + XML_RNGP_INCLUDE_RECURSE, /* 1044 */ + XML_RNGP_INTERLEAVE_ADD, /* 1045 */ + XML_RNGP_INTERLEAVE_CREATE_FAILED, /* 1046 */ + XML_RNGP_INTERLEAVE_EMPTY, /* 1047 */ + XML_RNGP_INTERLEAVE_NO_CONTENT, /* 1048 */ + XML_RNGP_INVALID_DEFINE_NAME, /* 1049 */ + XML_RNGP_INVALID_URI, /* 1050 */ + XML_RNGP_INVALID_VALUE, /* 1051 */ + XML_RNGP_MISSING_HREF, /* 1052 */ + XML_RNGP_NAME_MISSING, /* 1053 */ + XML_RNGP_NEED_COMBINE, /* 1054 */ + XML_RNGP_NOTALLOWED_NOT_EMPTY, /* 1055 */ + XML_RNGP_NSNAME_ATTR_ANCESTOR, /* 1056 */ + XML_RNGP_NSNAME_NO_NS, /* 1057 */ + XML_RNGP_PARAM_FORBIDDEN, /* 1058 */ + XML_RNGP_PARAM_NAME_MISSING, /* 1059 */ + XML_RNGP_PARENTREF_CREATE_FAILED, /* 1060 */ + XML_RNGP_PARENTREF_NAME_INVALID, /* 1061 */ + XML_RNGP_PARENTREF_NO_NAME, /* 1062 */ + XML_RNGP_PARENTREF_NO_PARENT, /* 1063 */ + XML_RNGP_PARENTREF_NOT_EMPTY, /* 1064 */ + XML_RNGP_PARSE_ERROR, /* 1065 */ + XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, /* 1066 */ + XML_RNGP_PAT_ATTR_ATTR, /* 1067 */ + XML_RNGP_PAT_ATTR_ELEM, /* 1068 */ + XML_RNGP_PAT_DATA_EXCEPT_ATTR, /* 1069 */ + XML_RNGP_PAT_DATA_EXCEPT_ELEM, /* 1070 */ + XML_RNGP_PAT_DATA_EXCEPT_EMPTY, /* 1071 */ + XML_RNGP_PAT_DATA_EXCEPT_GROUP, /* 1072 */ + XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, /* 1073 */ + XML_RNGP_PAT_DATA_EXCEPT_LIST, /* 1074 */ + XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, /* 1075 */ + XML_RNGP_PAT_DATA_EXCEPT_REF, /* 1076 */ + XML_RNGP_PAT_DATA_EXCEPT_TEXT, /* 1077 */ + XML_RNGP_PAT_LIST_ATTR, /* 1078 */ + XML_RNGP_PAT_LIST_ELEM, /* 1079 */ + XML_RNGP_PAT_LIST_INTERLEAVE, /* 1080 */ + XML_RNGP_PAT_LIST_LIST, /* 1081 */ + XML_RNGP_PAT_LIST_REF, /* 1082 */ + XML_RNGP_PAT_LIST_TEXT, /* 1083 */ + XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, /* 1084 */ + XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, /* 1085 */ + XML_RNGP_PAT_ONEMORE_GROUP_ATTR, /* 1086 */ + XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, /* 1087 */ + XML_RNGP_PAT_START_ATTR, /* 1088 */ + XML_RNGP_PAT_START_DATA, /* 1089 */ + XML_RNGP_PAT_START_EMPTY, /* 1090 */ + XML_RNGP_PAT_START_GROUP, /* 1091 */ + XML_RNGP_PAT_START_INTERLEAVE, /* 1092 */ + XML_RNGP_PAT_START_LIST, /* 1093 */ + XML_RNGP_PAT_START_ONEMORE, /* 1094 */ + XML_RNGP_PAT_START_TEXT, /* 1095 */ + XML_RNGP_PAT_START_VALUE, /* 1096 */ + XML_RNGP_PREFIX_UNDEFINED, /* 1097 */ + XML_RNGP_REF_CREATE_FAILED, /* 1098 */ + XML_RNGP_REF_CYCLE, /* 1099 */ + XML_RNGP_REF_NAME_INVALID, /* 1100 */ + XML_RNGP_REF_NO_DEF, /* 1101 */ + XML_RNGP_REF_NO_NAME, /* 1102 */ + XML_RNGP_REF_NOT_EMPTY, /* 1103 */ + XML_RNGP_START_CHOICE_AND_INTERLEAVE, /* 1104 */ + XML_RNGP_START_CONTENT, /* 1105 */ + XML_RNGP_START_EMPTY, /* 1106 */ + XML_RNGP_START_MISSING, /* 1107 */ + XML_RNGP_TEXT_EXPECTED, /* 1108 */ + XML_RNGP_TEXT_HAS_CHILD, /* 1109 */ + XML_RNGP_TYPE_MISSING, /* 1110 */ + XML_RNGP_TYPE_NOT_FOUND, /* 1111 */ + XML_RNGP_TYPE_VALUE, /* 1112 */ + XML_RNGP_UNKNOWN_ATTRIBUTE, /* 1113 */ + XML_RNGP_UNKNOWN_COMBINE, /* 1114 */ + XML_RNGP_UNKNOWN_CONSTRUCT, /* 1115 */ + XML_RNGP_UNKNOWN_TYPE_LIB, /* 1116 */ + XML_RNGP_URI_FRAGMENT, /* 1117 */ + XML_RNGP_URI_NOT_ABSOLUTE, /* 1118 */ + XML_RNGP_VALUE_EMPTY, /* 1119 */ + XML_RNGP_VALUE_NO_CONTENT, /* 1120 */ + XML_RNGP_XMLNS_NAME, /* 1121 */ + XML_RNGP_XML_NS, /* 1122 */ + XML_XPATH_EXPRESSION_OK = 1200, + XML_XPATH_NUMBER_ERROR, /* 1201 */ + XML_XPATH_UNFINISHED_LITERAL_ERROR, /* 1202 */ + XML_XPATH_START_LITERAL_ERROR, /* 1203 */ + XML_XPATH_VARIABLE_REF_ERROR, /* 1204 */ + XML_XPATH_UNDEF_VARIABLE_ERROR, /* 1205 */ + XML_XPATH_INVALID_PREDICATE_ERROR, /* 1206 */ + XML_XPATH_EXPR_ERROR, /* 1207 */ + XML_XPATH_UNCLOSED_ERROR, /* 1208 */ + XML_XPATH_UNKNOWN_FUNC_ERROR, /* 1209 */ + XML_XPATH_INVALID_OPERAND, /* 1210 */ + XML_XPATH_INVALID_TYPE, /* 1211 */ + XML_XPATH_INVALID_ARITY, /* 1212 */ + XML_XPATH_INVALID_CTXT_SIZE, /* 1213 */ + XML_XPATH_INVALID_CTXT_POSITION, /* 1214 */ + XML_XPATH_MEMORY_ERROR, /* 1215 */ + XML_XPTR_SYNTAX_ERROR, /* 1216 */ + XML_XPTR_RESOURCE_ERROR, /* 1217 */ + XML_XPTR_SUB_RESOURCE_ERROR, /* 1218 */ + XML_XPATH_UNDEF_PREFIX_ERROR, /* 1219 */ + XML_XPATH_ENCODING_ERROR, /* 1220 */ + XML_XPATH_INVALID_CHAR_ERROR, /* 1221 */ + XML_TREE_INVALID_HEX = 1300, + XML_TREE_INVALID_DEC, /* 1301 */ + XML_TREE_UNTERMINATED_ENTITY, /* 1302 */ + XML_TREE_NOT_UTF8, /* 1303 */ + XML_SAVE_NOT_UTF8 = 1400, + XML_SAVE_CHAR_INVALID, /* 1401 */ + XML_SAVE_NO_DOCTYPE, /* 1402 */ + XML_SAVE_UNKNOWN_ENCODING, /* 1403 */ + XML_REGEXP_COMPILE_ERROR = 1450, + XML_IO_UNKNOWN = 1500, + XML_IO_EACCES, /* 1501 */ + XML_IO_EAGAIN, /* 1502 */ + XML_IO_EBADF, /* 1503 */ + XML_IO_EBADMSG, /* 1504 */ + XML_IO_EBUSY, /* 1505 */ + XML_IO_ECANCELED, /* 1506 */ + XML_IO_ECHILD, /* 1507 */ + XML_IO_EDEADLK, /* 1508 */ + XML_IO_EDOM, /* 1509 */ + XML_IO_EEXIST, /* 1510 */ + XML_IO_EFAULT, /* 1511 */ + XML_IO_EFBIG, /* 1512 */ + XML_IO_EINPROGRESS, /* 1513 */ + XML_IO_EINTR, /* 1514 */ + XML_IO_EINVAL, /* 1515 */ + XML_IO_EIO, /* 1516 */ + XML_IO_EISDIR, /* 1517 */ + XML_IO_EMFILE, /* 1518 */ + XML_IO_EMLINK, /* 1519 */ + XML_IO_EMSGSIZE, /* 1520 */ + XML_IO_ENAMETOOLONG, /* 1521 */ + XML_IO_ENFILE, /* 1522 */ + XML_IO_ENODEV, /* 1523 */ + XML_IO_ENOENT, /* 1524 */ + XML_IO_ENOEXEC, /* 1525 */ + XML_IO_ENOLCK, /* 1526 */ + XML_IO_ENOMEM, /* 1527 */ + XML_IO_ENOSPC, /* 1528 */ + XML_IO_ENOSYS, /* 1529 */ + XML_IO_ENOTDIR, /* 1530 */ + XML_IO_ENOTEMPTY, /* 1531 */ + XML_IO_ENOTSUP, /* 1532 */ + XML_IO_ENOTTY, /* 1533 */ + XML_IO_ENXIO, /* 1534 */ + XML_IO_EPERM, /* 1535 */ + XML_IO_EPIPE, /* 1536 */ + XML_IO_ERANGE, /* 1537 */ + XML_IO_EROFS, /* 1538 */ + XML_IO_ESPIPE, /* 1539 */ + XML_IO_ESRCH, /* 1540 */ + XML_IO_ETIMEDOUT, /* 1541 */ + XML_IO_EXDEV, /* 1542 */ + XML_IO_NETWORK_ATTEMPT, /* 1543 */ + XML_IO_ENCODER, /* 1544 */ + XML_IO_FLUSH, /* 1545 */ + XML_IO_WRITE, /* 1546 */ + XML_IO_NO_INPUT, /* 1547 */ + XML_IO_BUFFER_FULL, /* 1548 */ + XML_IO_LOAD_ERROR, /* 1549 */ + XML_IO_ENOTSOCK, /* 1550 */ + XML_IO_EISCONN, /* 1551 */ + XML_IO_ECONNREFUSED, /* 1552 */ + XML_IO_ENETUNREACH, /* 1553 */ + XML_IO_EADDRINUSE, /* 1554 */ + XML_IO_EALREADY, /* 1555 */ + XML_IO_EAFNOSUPPORT, /* 1556 */ + XML_XINCLUDE_RECURSION=1600, + XML_XINCLUDE_PARSE_VALUE, /* 1601 */ + XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */ + XML_XINCLUDE_NO_HREF, /* 1603 */ + XML_XINCLUDE_NO_FALLBACK, /* 1604 */ + XML_XINCLUDE_HREF_URI, /* 1605 */ + XML_XINCLUDE_TEXT_FRAGMENT, /* 1606 */ + XML_XINCLUDE_TEXT_DOCUMENT, /* 1607 */ + XML_XINCLUDE_INVALID_CHAR, /* 1608 */ + XML_XINCLUDE_BUILD_FAILED, /* 1609 */ + XML_XINCLUDE_UNKNOWN_ENCODING, /* 1610 */ + XML_XINCLUDE_MULTIPLE_ROOT, /* 1611 */ + XML_XINCLUDE_XPTR_FAILED, /* 1612 */ + XML_XINCLUDE_XPTR_RESULT, /* 1613 */ + XML_XINCLUDE_INCLUDE_IN_INCLUDE, /* 1614 */ + XML_XINCLUDE_FALLBACKS_IN_INCLUDE, /* 1615 */ + XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, /* 1616 */ + XML_XINCLUDE_DEPRECATED_NS, /* 1617 */ + XML_XINCLUDE_FRAGMENT_ID, /* 1618 */ + XML_CATALOG_MISSING_ATTR = 1650, + XML_CATALOG_ENTRY_BROKEN, /* 1651 */ + XML_CATALOG_PREFER_VALUE, /* 1652 */ + XML_CATALOG_NOT_CATALOG, /* 1653 */ + XML_CATALOG_RECURSION, /* 1654 */ + XML_SCHEMAP_PREFIX_UNDEFINED = 1700, + XML_SCHEMAP_ATTRFORMDEFAULT_VALUE, /* 1701 */ + XML_SCHEMAP_ATTRGRP_NONAME_NOREF, /* 1702 */ + XML_SCHEMAP_ATTR_NONAME_NOREF, /* 1703 */ + XML_SCHEMAP_COMPLEXTYPE_NONAME_NOREF, /* 1704 */ + XML_SCHEMAP_ELEMFORMDEFAULT_VALUE, /* 1705 */ + XML_SCHEMAP_ELEM_NONAME_NOREF, /* 1706 */ + XML_SCHEMAP_EXTENSION_NO_BASE, /* 1707 */ + XML_SCHEMAP_FACET_NO_VALUE, /* 1708 */ + XML_SCHEMAP_FAILED_BUILD_IMPORT, /* 1709 */ + XML_SCHEMAP_GROUP_NONAME_NOREF, /* 1710 */ + XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI, /* 1711 */ + XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, /* 1712 */ + XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI, /* 1713 */ + XML_SCHEMAP_INVALID_BOOLEAN, /* 1714 */ + XML_SCHEMAP_INVALID_ENUM, /* 1715 */ + XML_SCHEMAP_INVALID_FACET, /* 1716 */ + XML_SCHEMAP_INVALID_FACET_VALUE, /* 1717 */ + XML_SCHEMAP_INVALID_MAXOCCURS, /* 1718 */ + XML_SCHEMAP_INVALID_MINOCCURS, /* 1719 */ + XML_SCHEMAP_INVALID_REF_AND_SUBTYPE, /* 1720 */ + XML_SCHEMAP_INVALID_WHITE_SPACE, /* 1721 */ + XML_SCHEMAP_NOATTR_NOREF, /* 1722 */ + XML_SCHEMAP_NOTATION_NO_NAME, /* 1723 */ + XML_SCHEMAP_NOTYPE_NOREF, /* 1724 */ + XML_SCHEMAP_REF_AND_SUBTYPE, /* 1725 */ + XML_SCHEMAP_RESTRICTION_NONAME_NOREF, /* 1726 */ + XML_SCHEMAP_SIMPLETYPE_NONAME, /* 1727 */ + XML_SCHEMAP_TYPE_AND_SUBTYPE, /* 1728 */ + XML_SCHEMAP_UNKNOWN_ALL_CHILD, /* 1729 */ + XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD, /* 1730 */ + XML_SCHEMAP_UNKNOWN_ATTR_CHILD, /* 1731 */ + XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD, /* 1732 */ + XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP, /* 1733 */ + XML_SCHEMAP_UNKNOWN_BASE_TYPE, /* 1734 */ + XML_SCHEMAP_UNKNOWN_CHOICE_CHILD, /* 1735 */ + XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD, /* 1736 */ + XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD, /* 1737 */ + XML_SCHEMAP_UNKNOWN_ELEM_CHILD, /* 1738 */ + XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD, /* 1739 */ + XML_SCHEMAP_UNKNOWN_FACET_CHILD, /* 1740 */ + XML_SCHEMAP_UNKNOWN_FACET_TYPE, /* 1741 */ + XML_SCHEMAP_UNKNOWN_GROUP_CHILD, /* 1742 */ + XML_SCHEMAP_UNKNOWN_IMPORT_CHILD, /* 1743 */ + XML_SCHEMAP_UNKNOWN_LIST_CHILD, /* 1744 */ + XML_SCHEMAP_UNKNOWN_NOTATION_CHILD, /* 1745 */ + XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD, /* 1746 */ + XML_SCHEMAP_UNKNOWN_REF, /* 1747 */ + XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD, /* 1748 */ + XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD, /* 1749 */ + XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD, /* 1750 */ + XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD, /* 1751 */ + XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD, /* 1752 */ + XML_SCHEMAP_UNKNOWN_TYPE, /* 1753 */ + XML_SCHEMAP_UNKNOWN_UNION_CHILD, /* 1754 */ + XML_SCHEMAP_ELEM_DEFAULT_FIXED, /* 1755 */ + XML_SCHEMAP_REGEXP_INVALID, /* 1756 */ + XML_SCHEMAP_FAILED_LOAD, /* 1757 */ + XML_SCHEMAP_NOTHING_TO_PARSE, /* 1758 */ + XML_SCHEMAP_NOROOT, /* 1759 */ + XML_SCHEMAP_REDEFINED_GROUP, /* 1760 */ + XML_SCHEMAP_REDEFINED_TYPE, /* 1761 */ + XML_SCHEMAP_REDEFINED_ELEMENT, /* 1762 */ + XML_SCHEMAP_REDEFINED_ATTRGROUP, /* 1763 */ + XML_SCHEMAP_REDEFINED_ATTR, /* 1764 */ + XML_SCHEMAP_REDEFINED_NOTATION, /* 1765 */ + XML_SCHEMAP_FAILED_PARSE, /* 1766 */ + XML_SCHEMAP_UNKNOWN_PREFIX, /* 1767 */ + XML_SCHEMAP_DEF_AND_PREFIX, /* 1768 */ + XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD, /* 1769 */ + XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI, /* 1770 */ + XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI, /* 1771 */ + XML_SCHEMAP_NOT_SCHEMA, /* 1772 */ + XML_SCHEMAP_UNKNOWN_MEMBER_TYPE, /* 1773 */ + XML_SCHEMAP_INVALID_ATTR_USE, /* 1774 */ + XML_SCHEMAP_RECURSIVE, /* 1775 */ + XML_SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE, /* 1776 */ + XML_SCHEMAP_INVALID_ATTR_COMBINATION, /* 1777 */ + XML_SCHEMAP_INVALID_ATTR_INLINE_COMBINATION, /* 1778 */ + XML_SCHEMAP_MISSING_SIMPLETYPE_CHILD, /* 1779 */ + XML_SCHEMAP_INVALID_ATTR_NAME, /* 1780 */ + XML_SCHEMAP_REF_AND_CONTENT, /* 1781 */ + XML_SCHEMAP_CT_PROPS_CORRECT_1, /* 1782 */ + XML_SCHEMAP_CT_PROPS_CORRECT_2, /* 1783 */ + XML_SCHEMAP_CT_PROPS_CORRECT_3, /* 1784 */ + XML_SCHEMAP_CT_PROPS_CORRECT_4, /* 1785 */ + XML_SCHEMAP_CT_PROPS_CORRECT_5, /* 1786 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, /* 1787 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1, /* 1788 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2, /* 1789 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2, /* 1790 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3, /* 1791 */ + XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER, /* 1792 */ + XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE, /* 1793 */ + XML_SCHEMAP_UNION_NOT_EXPRESSIBLE, /* 1794 */ + XML_SCHEMAP_SRC_IMPORT_3_1, /* 1795 */ + XML_SCHEMAP_SRC_IMPORT_3_2, /* 1796 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1, /* 1797 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2, /* 1798 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3, /* 1799 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_3, /* 1800 */ + XML_SCHEMAV_NOROOT = 1801, + XML_SCHEMAV_UNDECLAREDELEM, /* 1802 */ + XML_SCHEMAV_NOTTOPLEVEL, /* 1803 */ + XML_SCHEMAV_MISSING, /* 1804 */ + XML_SCHEMAV_WRONGELEM, /* 1805 */ + XML_SCHEMAV_NOTYPE, /* 1806 */ + XML_SCHEMAV_NOROLLBACK, /* 1807 */ + XML_SCHEMAV_ISABSTRACT, /* 1808 */ + XML_SCHEMAV_NOTEMPTY, /* 1809 */ + XML_SCHEMAV_ELEMCONT, /* 1810 */ + XML_SCHEMAV_HAVEDEFAULT, /* 1811 */ + XML_SCHEMAV_NOTNILLABLE, /* 1812 */ + XML_SCHEMAV_EXTRACONTENT, /* 1813 */ + XML_SCHEMAV_INVALIDATTR, /* 1814 */ + XML_SCHEMAV_INVALIDELEM, /* 1815 */ + XML_SCHEMAV_NOTDETERMINIST, /* 1816 */ + XML_SCHEMAV_CONSTRUCT, /* 1817 */ + XML_SCHEMAV_INTERNAL, /* 1818 */ + XML_SCHEMAV_NOTSIMPLE, /* 1819 */ + XML_SCHEMAV_ATTRUNKNOWN, /* 1820 */ + XML_SCHEMAV_ATTRINVALID, /* 1821 */ + XML_SCHEMAV_VALUE, /* 1822 */ + XML_SCHEMAV_FACET, /* 1823 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, /* 1824 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2, /* 1825 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3, /* 1826 */ + XML_SCHEMAV_CVC_TYPE_3_1_1, /* 1827 */ + XML_SCHEMAV_CVC_TYPE_3_1_2, /* 1828 */ + XML_SCHEMAV_CVC_FACET_VALID, /* 1829 */ + XML_SCHEMAV_CVC_LENGTH_VALID, /* 1830 */ + XML_SCHEMAV_CVC_MINLENGTH_VALID, /* 1831 */ + XML_SCHEMAV_CVC_MAXLENGTH_VALID, /* 1832 */ + XML_SCHEMAV_CVC_MININCLUSIVE_VALID, /* 1833 */ + XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID, /* 1834 */ + XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID, /* 1835 */ + XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID, /* 1836 */ + XML_SCHEMAV_CVC_TOTALDIGITS_VALID, /* 1837 */ + XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID, /* 1838 */ + XML_SCHEMAV_CVC_PATTERN_VALID, /* 1839 */ + XML_SCHEMAV_CVC_ENUMERATION_VALID, /* 1840 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1, /* 1841 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2, /* 1842 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3, /* 1843 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_4, /* 1844 */ + XML_SCHEMAV_CVC_ELT_1, /* 1845 */ + XML_SCHEMAV_CVC_ELT_2, /* 1846 */ + XML_SCHEMAV_CVC_ELT_3_1, /* 1847 */ + XML_SCHEMAV_CVC_ELT_3_2_1, /* 1848 */ + XML_SCHEMAV_CVC_ELT_3_2_2, /* 1849 */ + XML_SCHEMAV_CVC_ELT_4_1, /* 1850 */ + XML_SCHEMAV_CVC_ELT_4_2, /* 1851 */ + XML_SCHEMAV_CVC_ELT_4_3, /* 1852 */ + XML_SCHEMAV_CVC_ELT_5_1_1, /* 1853 */ + XML_SCHEMAV_CVC_ELT_5_1_2, /* 1854 */ + XML_SCHEMAV_CVC_ELT_5_2_1, /* 1855 */ + XML_SCHEMAV_CVC_ELT_5_2_2_1, /* 1856 */ + XML_SCHEMAV_CVC_ELT_5_2_2_2_1, /* 1857 */ + XML_SCHEMAV_CVC_ELT_5_2_2_2_2, /* 1858 */ + XML_SCHEMAV_CVC_ELT_6, /* 1859 */ + XML_SCHEMAV_CVC_ELT_7, /* 1860 */ + XML_SCHEMAV_CVC_ATTRIBUTE_1, /* 1861 */ + XML_SCHEMAV_CVC_ATTRIBUTE_2, /* 1862 */ + XML_SCHEMAV_CVC_ATTRIBUTE_3, /* 1863 */ + XML_SCHEMAV_CVC_ATTRIBUTE_4, /* 1864 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_1, /* 1865 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_1, /* 1866 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_2, /* 1867 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_4, /* 1868 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_5_1, /* 1869 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_5_2, /* 1870 */ + XML_SCHEMAV_ELEMENT_CONTENT, /* 1871 */ + XML_SCHEMAV_DOCUMENT_ELEMENT_MISSING, /* 1872 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_1, /* 1873 */ + XML_SCHEMAV_CVC_AU, /* 1874 */ + XML_SCHEMAV_CVC_TYPE_1, /* 1875 */ + XML_SCHEMAV_CVC_TYPE_2, /* 1876 */ + XML_SCHEMAV_CVC_IDC, /* 1877 */ + XML_SCHEMAV_CVC_WILDCARD, /* 1878 */ + XML_SCHEMAV_MISC, /* 1879 */ + XML_XPTR_UNKNOWN_SCHEME = 1900, + XML_XPTR_CHILDSEQ_START, /* 1901 */ + XML_XPTR_EVAL_FAILED, /* 1902 */ + XML_XPTR_EXTRA_OBJECTS, /* 1903 */ + XML_C14N_CREATE_CTXT = 1950, + XML_C14N_REQUIRES_UTF8, /* 1951 */ + XML_C14N_CREATE_STACK, /* 1952 */ + XML_C14N_INVALID_NODE, /* 1953 */ + XML_C14N_UNKNOW_NODE, /* 1954 */ + XML_C14N_RELATIVE_NAMESPACE, /* 1955 */ + XML_FTP_PASV_ANSWER = 2000, + XML_FTP_EPSV_ANSWER, /* 2001 */ + XML_FTP_ACCNT, /* 2002 */ + XML_FTP_URL_SYNTAX, /* 2003 */ + XML_HTTP_URL_SYNTAX = 2020, + XML_HTTP_USE_IP, /* 2021 */ + XML_HTTP_UNKNOWN_HOST, /* 2022 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_1 = 3000, + XML_SCHEMAP_SRC_SIMPLE_TYPE_2, /* 3001 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_3, /* 3002 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_4, /* 3003 */ + XML_SCHEMAP_SRC_RESOLVE, /* 3004 */ + XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE, /* 3005 */ + XML_SCHEMAP_SRC_LIST_ITEMTYPE_OR_SIMPLETYPE, /* 3006 */ + XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES, /* 3007 */ + XML_SCHEMAP_ST_PROPS_CORRECT_1, /* 3008 */ + XML_SCHEMAP_ST_PROPS_CORRECT_2, /* 3009 */ + XML_SCHEMAP_ST_PROPS_CORRECT_3, /* 3010 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_1, /* 3011 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_2, /* 3012 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1, /* 3013 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_2, /* 3014 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, /* 3015 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1, /* 3016 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2, /* 3017 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1, /* 3018 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2, /* 3019 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3, /* 3020 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4, /* 3021 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_5, /* 3022 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_1, /* 3023 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1, /* 3024 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2, /* 3025 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2, /* 3026 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1, /* 3027 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3, /* 3028 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4, /* 3029 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_5, /* 3030 */ + XML_SCHEMAP_COS_ST_DERIVED_OK_2_1, /* 3031 */ + XML_SCHEMAP_COS_ST_DERIVED_OK_2_2, /* 3032 */ + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, /* 3033 */ + XML_SCHEMAP_S4S_ELEM_MISSING, /* 3034 */ + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, /* 3035 */ + XML_SCHEMAP_S4S_ATTR_MISSING, /* 3036 */ + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, /* 3037 */ + XML_SCHEMAP_SRC_ELEMENT_1, /* 3038 */ + XML_SCHEMAP_SRC_ELEMENT_2_1, /* 3039 */ + XML_SCHEMAP_SRC_ELEMENT_2_2, /* 3040 */ + XML_SCHEMAP_SRC_ELEMENT_3, /* 3041 */ + XML_SCHEMAP_P_PROPS_CORRECT_1, /* 3042 */ + XML_SCHEMAP_P_PROPS_CORRECT_2_1, /* 3043 */ + XML_SCHEMAP_P_PROPS_CORRECT_2_2, /* 3044 */ + XML_SCHEMAP_E_PROPS_CORRECT_2, /* 3045 */ + XML_SCHEMAP_E_PROPS_CORRECT_3, /* 3046 */ + XML_SCHEMAP_E_PROPS_CORRECT_4, /* 3047 */ + XML_SCHEMAP_E_PROPS_CORRECT_5, /* 3048 */ + XML_SCHEMAP_E_PROPS_CORRECT_6, /* 3049 */ + XML_SCHEMAP_SRC_INCLUDE, /* 3050 */ + XML_SCHEMAP_SRC_ATTRIBUTE_1, /* 3051 */ + XML_SCHEMAP_SRC_ATTRIBUTE_2, /* 3052 */ + XML_SCHEMAP_SRC_ATTRIBUTE_3_1, /* 3053 */ + XML_SCHEMAP_SRC_ATTRIBUTE_3_2, /* 3054 */ + XML_SCHEMAP_SRC_ATTRIBUTE_4, /* 3055 */ + XML_SCHEMAP_NO_XMLNS, /* 3056 */ + XML_SCHEMAP_NO_XSI, /* 3057 */ + XML_SCHEMAP_COS_VALID_DEFAULT_1, /* 3058 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_1, /* 3059 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_2_1, /* 3060 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_2_2, /* 3061 */ + XML_SCHEMAP_CVC_SIMPLE_TYPE, /* 3062 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_1, /* 3063 */ + XML_SCHEMAP_SRC_IMPORT_1_1, /* 3064 */ + XML_SCHEMAP_SRC_IMPORT_1_2, /* 3065 */ + XML_SCHEMAP_SRC_IMPORT_2, /* 3066 */ + XML_SCHEMAP_SRC_IMPORT_2_1, /* 3067 */ + XML_SCHEMAP_SRC_IMPORT_2_2, /* 3068 */ + XML_SCHEMAP_INTERNAL, /* 3069 non-W3C */ + XML_SCHEMAP_NOT_DETERMINISTIC, /* 3070 non-W3C */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_1, /* 3071 */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_2, /* 3072 */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_3, /* 3073 */ + XML_SCHEMAP_MG_PROPS_CORRECT_1, /* 3074 */ + XML_SCHEMAP_MG_PROPS_CORRECT_2, /* 3075 */ + XML_SCHEMAP_SRC_CT_1, /* 3076 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3, /* 3077 */ + XML_SCHEMAP_AU_PROPS_CORRECT_2, /* 3078 */ + XML_SCHEMAP_A_PROPS_CORRECT_2, /* 3079 */ + XML_SCHEMAP_C_PROPS_CORRECT, /* 3080 */ + XML_SCHEMAP_SRC_REDEFINE, /* 3081 */ + XML_SCHEMAP_SRC_IMPORT, /* 3082 */ + XML_SCHEMAP_WARN_SKIP_SCHEMA, /* 3083 */ + XML_SCHEMAP_WARN_UNLOCATED_SCHEMA, /* 3084 */ + XML_SCHEMAP_WARN_ATTR_REDECL_PROH, /* 3085 */ + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, /* 3085 */ + XML_SCHEMAP_AG_PROPS_CORRECT, /* 3086 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_2, /* 3087 */ + XML_SCHEMAP_AU_PROPS_CORRECT, /* 3088 */ + XML_SCHEMAP_A_PROPS_CORRECT_3, /* 3089 */ + XML_SCHEMAP_COS_ALL_LIMITED, /* 3090 */ + XML_SCHEMATRONV_ASSERT = 4000, /* 4000 */ + XML_SCHEMATRONV_REPORT, + XML_MODULE_OPEN = 4900, /* 4900 */ + XML_MODULE_CLOSE, /* 4901 */ + XML_CHECK_FOUND_ELEMENT = 5000, + XML_CHECK_FOUND_ATTRIBUTE, /* 5001 */ + XML_CHECK_FOUND_TEXT, /* 5002 */ + XML_CHECK_FOUND_CDATA, /* 5003 */ + XML_CHECK_FOUND_ENTITYREF, /* 5004 */ + XML_CHECK_FOUND_ENTITY, /* 5005 */ + XML_CHECK_FOUND_PI, /* 5006 */ + XML_CHECK_FOUND_COMMENT, /* 5007 */ + XML_CHECK_FOUND_DOCTYPE, /* 5008 */ + XML_CHECK_FOUND_FRAGMENT, /* 5009 */ + XML_CHECK_FOUND_NOTATION, /* 5010 */ + XML_CHECK_UNKNOWN_NODE, /* 5011 */ + XML_CHECK_ENTITY_TYPE, /* 5012 */ + XML_CHECK_NO_PARENT, /* 5013 */ + XML_CHECK_NO_DOC, /* 5014 */ + XML_CHECK_NO_NAME, /* 5015 */ + XML_CHECK_NO_ELEM, /* 5016 */ + XML_CHECK_WRONG_DOC, /* 5017 */ + XML_CHECK_NO_PREV, /* 5018 */ + XML_CHECK_WRONG_PREV, /* 5019 */ + XML_CHECK_NO_NEXT, /* 5020 */ + XML_CHECK_WRONG_NEXT, /* 5021 */ + XML_CHECK_NOT_DTD, /* 5022 */ + XML_CHECK_NOT_ATTR, /* 5023 */ + XML_CHECK_NOT_ATTR_DECL, /* 5024 */ + XML_CHECK_NOT_ELEM_DECL, /* 5025 */ + XML_CHECK_NOT_ENTITY_DECL, /* 5026 */ + XML_CHECK_NOT_NS_DECL, /* 5027 */ + XML_CHECK_NO_HREF, /* 5028 */ + XML_CHECK_WRONG_PARENT,/* 5029 */ + XML_CHECK_NS_SCOPE, /* 5030 */ + XML_CHECK_NS_ANCESTOR, /* 5031 */ + XML_CHECK_NOT_UTF8, /* 5032 */ + XML_CHECK_NO_DICT, /* 5033 */ + XML_CHECK_NOT_NCNAME, /* 5034 */ + XML_CHECK_OUTSIDE_DICT, /* 5035 */ + XML_CHECK_WRONG_NAME, /* 5036 */ + XML_CHECK_NAME_NOT_NULL, /* 5037 */ + XML_I18N_NO_NAME = 6000, + XML_I18N_NO_HANDLER, /* 6001 */ + XML_I18N_EXCESS_HANDLER, /* 6002 */ + XML_I18N_CONV_FAILED, /* 6003 */ + XML_I18N_NO_OUTPUT, /* 6004 */ + XML_BUF_OVERFLOW = 7000 +} xmlParserErrors; + +/** + * xmlGenericErrorFunc: + * @ctx: a parsing context + * @msg: the message + * @...: the extra arguments of the varags to format the message + * + * Signature of the function to use when there is an error and + * no parsing or validity context available . + */ +typedef void (XMLCDECL *xmlGenericErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +/** + * xmlStructuredErrorFunc: + * @userData: user provided data for the error callback + * @error: the error being raised. + * + * Signature of the function to use when there is an error and + * the module handles the new error reporting mechanism. + */ +typedef void (XMLCALL *xmlStructuredErrorFunc) (void *userData, xmlErrorPtr error); + +/* + * Use the following function to reset the two global variables + * xmlGenericError and xmlGenericErrorContext. + */ +XMLPUBFUN void XMLCALL + xmlSetGenericErrorFunc (void *ctx, + xmlGenericErrorFunc handler); +XMLPUBFUN void XMLCALL + initGenericErrorDefaultFunc (xmlGenericErrorFunc *handler); + +XMLPUBFUN void XMLCALL + xmlSetStructuredErrorFunc (void *ctx, + xmlStructuredErrorFunc handler); +/* + * Default message routines used by SAX and Valid context for error + * and warning reporting. + */ +XMLPUBFUN void XMLCDECL + xmlParserError (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCDECL + xmlParserWarning (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCDECL + xmlParserValidityError (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCDECL + xmlParserValidityWarning (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCALL + xmlParserPrintFileInfo (xmlParserInputPtr input); +XMLPUBFUN void XMLCALL + xmlParserPrintFileContext (xmlParserInputPtr input); + +/* + * Extended error information routines + */ +XMLPUBFUN xmlErrorPtr XMLCALL + xmlGetLastError (void); +XMLPUBFUN void XMLCALL + xmlResetLastError (void); +XMLPUBFUN xmlErrorPtr XMLCALL + xmlCtxtGetLastError (void *ctx); +XMLPUBFUN void XMLCALL + xmlCtxtResetLastError (void *ctx); +XMLPUBFUN void XMLCALL + xmlResetError (xmlErrorPtr err); +XMLPUBFUN int XMLCALL + xmlCopyError (xmlErrorPtr from, + xmlErrorPtr to); + +#ifdef IN_LIBXML +/* + * Internal callback reporting routine + */ +XMLPUBFUN void XMLCALL + __xmlRaiseError (xmlStructuredErrorFunc schannel, + xmlGenericErrorFunc channel, + void *data, + void *ctx, + void *node, + int domain, + int code, + xmlErrorLevel level, + const char *file, + int line, + const char *str1, + const char *str2, + const char *str3, + int int1, + int col, + const char *msg, + ...) LIBXML_ATTR_FORMAT(16,17); +XMLPUBFUN void XMLCALL + __xmlSimpleError (int domain, + int code, + xmlNodePtr node, + const char *msg, + const char *extra); +#endif +#ifdef __cplusplus +} +#endif +#endif /* __XML_ERROR_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlexports.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlexports.h new file mode 100644 index 0000000..2c79f81 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlexports.h @@ -0,0 +1,162 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * Description: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + * + * Author: Igor Zlatovic + */ + +#ifndef __XML_EXPORTS_H__ +#define __XML_EXPORTS_H__ + +/** + * XMLPUBFUN, XMLPUBVAR, XMLCALL + * + * Macros which declare an exportable function, an exportable variable and + * the calling convention used for functions. + * + * Please use an extra block for every platform/compiler combination when + * modifying this, rather than overlong #ifdef lines. This helps + * readability as well as the fact that different compilers on the same + * platform might need different definitions. + */ + +/** + * XMLPUBFUN: + * + * Macros which declare an exportable function + */ +#define XMLPUBFUN +/** + * XMLPUBVAR: + * + * Macros which declare an exportable variable + */ +#define XMLPUBVAR extern +/** + * XMLCALL: + * + * Macros which declare the called convention for exported functions + */ +#define XMLCALL +/** + * XMLCDECL: + * + * Macro which declares the calling convention for exported functions that + * use '...'. + */ +#define XMLCDECL + +/** DOC_DISABLE */ + +/* Windows platform with MS compiler */ +#if defined(_WIN32) && defined(_MSC_VER) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR extern + #endif + #endif + #if defined(LIBXML_FASTCALL) + #define XMLCALL __fastcall + #else + #define XMLCALL __cdecl + #endif + #define XMLCDECL __cdecl + #if !defined _REENTRANT + #define _REENTRANT + #endif +#endif + +/* Windows platform with Borland compiler */ +#if defined(_WIN32) && defined(__BORLANDC__) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) extern + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR extern + #endif + #endif + #define XMLCALL __cdecl + #define XMLCDECL __cdecl + #if !defined _REENTRANT + #define _REENTRANT + #endif +#endif + +/* Windows platform with GNU compiler (Mingw) */ +#if defined(_WIN32) && defined(__MINGW32__) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + /* + * if defined(IN_LIBXML) this raises problems on mingw with msys + * _imp__xmlFree listed as missing. Try to workaround the problem + * by also making that declaration when compiling client code. + */ + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) extern + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR extern + #endif + #endif + #define XMLCALL __cdecl + #define XMLCDECL __cdecl + #if !defined _REENTRANT + #define _REENTRANT + #endif +#endif + +/* Cygwin platform, GNU compiler */ +#if defined(_WIN32) && defined(__CYGWIN__) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR + #endif + #endif + #define XMLCALL __cdecl + #define XMLCDECL __cdecl +#endif + +/* Compatibility */ +#if !defined(LIBXML_DLL_IMPORT) +#define LIBXML_DLL_IMPORT XMLPUBVAR +#endif + +#endif /* __XML_EXPORTS_H__ */ + + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlmemory.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlmemory.h new file mode 100644 index 0000000..17e375a --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlmemory.h @@ -0,0 +1,224 @@ +/* + * Summary: interface for the memory allocator + * Description: provides interfaces for the memory allocator, + * including debugging capabilities. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __DEBUG_MEMORY_ALLOC__ +#define __DEBUG_MEMORY_ALLOC__ + +#include +#include + +/** + * DEBUG_MEMORY: + * + * DEBUG_MEMORY replaces the allocator with a collect and debug + * shell to the libc allocator. + * DEBUG_MEMORY should only be activated when debugging + * libxml i.e. if libxml has been configured with --with-debug-mem too. + */ +/* #define DEBUG_MEMORY_FREED */ +/* #define DEBUG_MEMORY_LOCATION */ + +#ifdef DEBUG +#ifndef DEBUG_MEMORY +#define DEBUG_MEMORY +#endif +#endif + +/** + * DEBUG_MEMORY_LOCATION: + * + * DEBUG_MEMORY_LOCATION should be activated only when debugging + * libxml i.e. if libxml has been configured with --with-debug-mem too. + */ +#ifdef DEBUG_MEMORY_LOCATION +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The XML memory wrapper support 4 basic overloadable functions. + */ +/** + * xmlFreeFunc: + * @mem: an already allocated block of memory + * + * Signature for a free() implementation. + */ +typedef void (XMLCALL *xmlFreeFunc)(void *mem); +/** + * xmlMallocFunc: + * @size: the size requested in bytes + * + * Signature for a malloc() implementation. + * + * Returns a pointer to the newly allocated block or NULL in case of error. + */ +typedef void *(LIBXML_ATTR_ALLOC_SIZE(1) XMLCALL *xmlMallocFunc)(size_t size); + +/** + * xmlReallocFunc: + * @mem: an already allocated block of memory + * @size: the new size requested in bytes + * + * Signature for a realloc() implementation. + * + * Returns a pointer to the newly reallocated block or NULL in case of error. + */ +typedef void *(XMLCALL *xmlReallocFunc)(void *mem, size_t size); + +/** + * xmlStrdupFunc: + * @str: a zero terminated string + * + * Signature for an strdup() implementation. + * + * Returns the copy of the string or NULL in case of error. + */ +typedef char *(XMLCALL *xmlStrdupFunc)(const char *str); + +/* + * The 4 interfaces used for all memory handling within libxml. +LIBXML_DLL_IMPORT xmlFreeFunc xmlFree; +LIBXML_DLL_IMPORT xmlMallocFunc xmlMalloc; +LIBXML_DLL_IMPORT xmlMallocFunc xmlMallocAtomic; +LIBXML_DLL_IMPORT xmlReallocFunc xmlRealloc; +LIBXML_DLL_IMPORT xmlStrdupFunc xmlMemStrdup; + */ + +/* + * The way to overload the existing functions. + * The xmlGc function have an extra entry for atomic block + * allocations useful for garbage collected memory allocators + */ +XMLPUBFUN int XMLCALL + xmlMemSetup (xmlFreeFunc freeFunc, + xmlMallocFunc mallocFunc, + xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc); +XMLPUBFUN int XMLCALL + xmlMemGet (xmlFreeFunc *freeFunc, + xmlMallocFunc *mallocFunc, + xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc); +XMLPUBFUN int XMLCALL + xmlGcMemSetup (xmlFreeFunc freeFunc, + xmlMallocFunc mallocFunc, + xmlMallocFunc mallocAtomicFunc, + xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc); +XMLPUBFUN int XMLCALL + xmlGcMemGet (xmlFreeFunc *freeFunc, + xmlMallocFunc *mallocFunc, + xmlMallocFunc *mallocAtomicFunc, + xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc); + +/* + * Initialization of the memory layer. + */ +XMLPUBFUN int XMLCALL + xmlInitMemory (void); + +/* + * Cleanup of the memory layer. + */ +XMLPUBFUN void XMLCALL + xmlCleanupMemory (void); +/* + * These are specific to the XML debug memory wrapper. + */ +XMLPUBFUN int XMLCALL + xmlMemUsed (void); +XMLPUBFUN int XMLCALL + xmlMemBlocks (void); +XMLPUBFUN void XMLCALL + xmlMemDisplay (FILE *fp); +XMLPUBFUN void XMLCALL + xmlMemDisplayLast(FILE *fp, long nbBytes); +XMLPUBFUN void XMLCALL + xmlMemShow (FILE *fp, int nr); +XMLPUBFUN void XMLCALL + xmlMemoryDump (void); +XMLPUBFUN void * XMLCALL + xmlMemMalloc (size_t size) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN void * XMLCALL + xmlMemRealloc (void *ptr,size_t size); +XMLPUBFUN void XMLCALL + xmlMemFree (void *ptr); +XMLPUBFUN char * XMLCALL + xmlMemoryStrdup (const char *str); +XMLPUBFUN void * XMLCALL + xmlMallocLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN void * XMLCALL + xmlReallocLoc (void *ptr, size_t size, const char *file, int line); +XMLPUBFUN void * XMLCALL + xmlMallocAtomicLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN char * XMLCALL + xmlMemStrdupLoc (const char *str, const char *file, int line); + + +#ifdef DEBUG_MEMORY_LOCATION +/** + * xmlMalloc: + * @size: number of bytes to allocate + * + * Wrapper for the malloc() function used in the XML library. + * + * Returns the pointer to the allocated area or NULL in case of error. + */ +#define xmlMalloc(size) xmlMallocLoc((size), __FILE__, __LINE__) +/** + * xmlMallocAtomic: + * @size: number of bytes to allocate + * + * Wrapper for the malloc() function used in the XML library for allocation + * of block not containing pointers to other areas. + * + * Returns the pointer to the allocated area or NULL in case of error. + */ +#define xmlMallocAtomic(size) xmlMallocAtomicLoc((size), __FILE__, __LINE__) +/** + * xmlRealloc: + * @ptr: pointer to the existing allocated area + * @size: number of bytes to allocate + * + * Wrapper for the realloc() function used in the XML library. + * + * Returns the pointer to the allocated area or NULL in case of error. + */ +#define xmlRealloc(ptr, size) xmlReallocLoc((ptr), (size), __FILE__, __LINE__) +/** + * xmlMemStrdup: + * @str: pointer to the existing string + * + * Wrapper for the strdup() function, xmlStrdup() is usually preferred. + * + * Returns the pointer to the allocated area or NULL in case of error. + */ +#define xmlMemStrdup(str) xmlMemStrdupLoc((str), __FILE__, __LINE__) + +#endif /* DEBUG_MEMORY_LOCATION */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#ifndef __XML_GLOBALS_H +#ifndef __XML_THREADS_H__ +#include +#include +#endif +#endif + +#endif /* __DEBUG_MEMORY_ALLOC__ */ + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlmodule.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlmodule.h new file mode 100644 index 0000000..9667820 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlmodule.h @@ -0,0 +1,57 @@ +/* + * Summary: dynamic module loading + * Description: basic API for dynamic module loading, used by + * libexslt added in 2.6.17 + * + * Copy: See Copyright for the status of this software. + * + * Author: Joel W. Reed + */ + +#ifndef __XML_MODULE_H__ +#define __XML_MODULE_H__ + +#include + +#ifdef LIBXML_MODULES_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlModulePtr: + * + * A handle to a dynamically loaded module + */ +typedef struct _xmlModule xmlModule; +typedef xmlModule *xmlModulePtr; + +/** + * xmlModuleOption: + * + * enumeration of options that can be passed down to xmlModuleOpen() + */ +typedef enum { + XML_MODULE_LAZY = 1, /* lazy binding */ + XML_MODULE_LOCAL= 2 /* local binding */ +} xmlModuleOption; + +XMLPUBFUN xmlModulePtr XMLCALL xmlModuleOpen (const char *filename, + int options); + +XMLPUBFUN int XMLCALL xmlModuleSymbol (xmlModulePtr module, + const char* name, + void **result); + +XMLPUBFUN int XMLCALL xmlModuleClose (xmlModulePtr module); + +XMLPUBFUN int XMLCALL xmlModuleFree (xmlModulePtr module); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_MODULES_ENABLED */ + +#endif /*__XML_MODULE_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlreader.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlreader.h new file mode 100644 index 0000000..2c99e3a --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlreader.h @@ -0,0 +1,428 @@ +/* + * Summary: the XMLReader implementation + * Description: API of the XML streaming API based on C# interfaces. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLREADER_H__ +#define __XML_XMLREADER_H__ + +#include +#include +#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlParserSeverities: + * + * How severe an error callback is when the per-reader error callback API + * is used. + */ +typedef enum { + XML_PARSER_SEVERITY_VALIDITY_WARNING = 1, + XML_PARSER_SEVERITY_VALIDITY_ERROR = 2, + XML_PARSER_SEVERITY_WARNING = 3, + XML_PARSER_SEVERITY_ERROR = 4 +} xmlParserSeverities; + +#ifdef LIBXML_READER_ENABLED + +/** + * xmlTextReaderMode: + * + * Internal state values for the reader. + */ +typedef enum { + XML_TEXTREADER_MODE_INITIAL = 0, + XML_TEXTREADER_MODE_INTERACTIVE = 1, + XML_TEXTREADER_MODE_ERROR = 2, + XML_TEXTREADER_MODE_EOF =3, + XML_TEXTREADER_MODE_CLOSED = 4, + XML_TEXTREADER_MODE_READING = 5 +} xmlTextReaderMode; + +/** + * xmlParserProperties: + * + * Some common options to use with xmlTextReaderSetParserProp, but it + * is better to use xmlParserOption and the xmlReaderNewxxx and + * xmlReaderForxxx APIs now. + */ +typedef enum { + XML_PARSER_LOADDTD = 1, + XML_PARSER_DEFAULTATTRS = 2, + XML_PARSER_VALIDATE = 3, + XML_PARSER_SUBST_ENTITIES = 4 +} xmlParserProperties; + +/** + * xmlReaderTypes: + * + * Predefined constants for the different types of nodes. + */ +typedef enum { + XML_READER_TYPE_NONE = 0, + XML_READER_TYPE_ELEMENT = 1, + XML_READER_TYPE_ATTRIBUTE = 2, + XML_READER_TYPE_TEXT = 3, + XML_READER_TYPE_CDATA = 4, + XML_READER_TYPE_ENTITY_REFERENCE = 5, + XML_READER_TYPE_ENTITY = 6, + XML_READER_TYPE_PROCESSING_INSTRUCTION = 7, + XML_READER_TYPE_COMMENT = 8, + XML_READER_TYPE_DOCUMENT = 9, + XML_READER_TYPE_DOCUMENT_TYPE = 10, + XML_READER_TYPE_DOCUMENT_FRAGMENT = 11, + XML_READER_TYPE_NOTATION = 12, + XML_READER_TYPE_WHITESPACE = 13, + XML_READER_TYPE_SIGNIFICANT_WHITESPACE = 14, + XML_READER_TYPE_END_ELEMENT = 15, + XML_READER_TYPE_END_ENTITY = 16, + XML_READER_TYPE_XML_DECLARATION = 17 +} xmlReaderTypes; + +/** + * xmlTextReader: + * + * Structure for an xmlReader context. + */ +typedef struct _xmlTextReader xmlTextReader; + +/** + * xmlTextReaderPtr: + * + * Pointer to an xmlReader context. + */ +typedef xmlTextReader *xmlTextReaderPtr; + +/* + * Constructors & Destructor + */ +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlNewTextReader (xmlParserInputBufferPtr input, + const char *URI); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlNewTextReaderFilename(const char *URI); + +XMLPUBFUN void XMLCALL + xmlFreeTextReader (xmlTextReaderPtr reader); + +XMLPUBFUN int XMLCALL + xmlTextReaderSetup(xmlTextReaderPtr reader, + xmlParserInputBufferPtr input, const char *URL, + const char *encoding, int options); + +/* + * Iterators + */ +XMLPUBFUN int XMLCALL + xmlTextReaderRead (xmlTextReaderPtr reader); + +#ifdef LIBXML_WRITER_ENABLED +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderReadInnerXml(xmlTextReaderPtr reader); + +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderReadOuterXml(xmlTextReaderPtr reader); +#endif + +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderReadString (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader); + +/* + * Attributes of the node + */ +XMLPUBFUN int XMLCALL + xmlTextReaderAttributeCount(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderDepth (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderHasAttributes(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderHasValue(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsDefault (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNodeType (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderQuoteChar (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderReadState (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader); + +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstLocalName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstPrefix (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstXmlLang (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstString (xmlTextReaderPtr reader, + const xmlChar *str); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstValue (xmlTextReaderPtr reader); + +/* + * use the Const version of the routine for + * better performance and simpler code + */ +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderLocalName (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderName (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderPrefix (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderXmlLang (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderValue (xmlTextReaderPtr reader); + +/* + * Methods of the XmlTextReader + */ +XMLPUBFUN int XMLCALL + xmlTextReaderClose (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderGetAttributeNo (xmlTextReaderPtr reader, + int no); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderGetAttribute (xmlTextReaderPtr reader, + const xmlChar *name); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderGetAttributeNs (xmlTextReaderPtr reader, + const xmlChar *localName, + const xmlChar *namespaceURI); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlTextReaderGetRemainder (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, + const xmlChar *prefix); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, + int no); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, + const xmlChar *name); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, + const xmlChar *localName, + const xmlChar *namespaceURI); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToElement (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNormalization (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstEncoding (xmlTextReaderPtr reader); + +/* + * Extensions + */ +XMLPUBFUN int XMLCALL + xmlTextReaderSetParserProp (xmlTextReaderPtr reader, + int prop, + int value); +XMLPUBFUN int XMLCALL + xmlTextReaderGetParserProp (xmlTextReaderPtr reader, + int prop); +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextReaderCurrentNode (xmlTextReaderPtr reader); + +XMLPUBFUN int XMLCALL + xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader); + +XMLPUBFUN int XMLCALL + xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader); + +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextReaderPreserve (xmlTextReaderPtr reader); +#ifdef LIBXML_PATTERN_ENABLED +XMLPUBFUN int XMLCALL + xmlTextReaderPreservePattern(xmlTextReaderPtr reader, + const xmlChar *pattern, + const xmlChar **namespaces); +#endif /* LIBXML_PATTERN_ENABLED */ +XMLPUBFUN xmlDocPtr XMLCALL + xmlTextReaderCurrentDoc (xmlTextReaderPtr reader); +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextReaderExpand (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNext (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNextSibling (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsValid (xmlTextReaderPtr reader); +#ifdef LIBXML_SCHEMAS_ENABLED +XMLPUBFUN int XMLCALL + xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, + const char *rng); +XMLPUBFUN int XMLCALL + xmlTextReaderRelaxNGValidateCtxt(xmlTextReaderPtr reader, + xmlRelaxNGValidCtxtPtr ctxt, + int options); + +XMLPUBFUN int XMLCALL + xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, + xmlRelaxNGPtr schema); +XMLPUBFUN int XMLCALL + xmlTextReaderSchemaValidate (xmlTextReaderPtr reader, + const char *xsd); +XMLPUBFUN int XMLCALL + xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader, + xmlSchemaValidCtxtPtr ctxt, + int options); +XMLPUBFUN int XMLCALL + xmlTextReaderSetSchema (xmlTextReaderPtr reader, + xmlSchemaPtr schema); +#endif +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderStandalone (xmlTextReaderPtr reader); + + +/* + * Index lookup + */ +XMLPUBFUN long XMLCALL + xmlTextReaderByteConsumed (xmlTextReaderPtr reader); + +/* + * New more complete APIs for simpler creation and reuse of readers + */ +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderWalker (xmlDocPtr doc); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForDoc (const xmlChar * cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForFile (const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +XMLPUBFUN int XMLCALL + xmlReaderNewWalker (xmlTextReaderPtr reader, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlReaderNewDoc (xmlTextReaderPtr reader, + const xmlChar * cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewFile (xmlTextReaderPtr reader, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewMemory (xmlTextReaderPtr reader, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewFd (xmlTextReaderPtr reader, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewIO (xmlTextReaderPtr reader, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +/* + * Error handling extensions + */ +typedef void * xmlTextReaderLocatorPtr; + +/** + * xmlTextReaderErrorFunc: + * @arg: the user argument + * @msg: the message + * @severity: the severity of the error + * @locator: a locator indicating where the error occured + * + * Signature of an error callback from a reader parser + */ +typedef void (XMLCALL *xmlTextReaderErrorFunc)(void *arg, + const char *msg, + xmlParserSeverities severity, + xmlTextReaderLocatorPtr locator); +XMLPUBFUN int XMLCALL + xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderLocatorBaseURI (xmlTextReaderLocatorPtr locator); +XMLPUBFUN void XMLCALL + xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc f, + void *arg); +XMLPUBFUN void XMLCALL + xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader, + xmlStructuredErrorFunc f, + void *arg); +XMLPUBFUN void XMLCALL + xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc *f, + void **arg); + +#endif /* LIBXML_READER_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XMLREADER_H__ */ + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlregexp.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlregexp.h new file mode 100644 index 0000000..7009645 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlregexp.h @@ -0,0 +1,222 @@ +/* + * Summary: regular expressions handling + * Description: basic API for libxml regular expressions handling used + * for XML Schemas and validation. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_REGEXP_H__ +#define __XML_REGEXP_H__ + +#include + +#ifdef LIBXML_REGEXP_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlRegexpPtr: + * + * A libxml regular expression, they can actually be far more complex + * thank the POSIX regex expressions. + */ +typedef struct _xmlRegexp xmlRegexp; +typedef xmlRegexp *xmlRegexpPtr; + +/** + * xmlRegExecCtxtPtr: + * + * A libxml progressive regular expression evaluation context + */ +typedef struct _xmlRegExecCtxt xmlRegExecCtxt; +typedef xmlRegExecCtxt *xmlRegExecCtxtPtr; + +#ifdef __cplusplus +} +#endif +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The POSIX like API + */ +XMLPUBFUN xmlRegexpPtr XMLCALL + xmlRegexpCompile (const xmlChar *regexp); +XMLPUBFUN void XMLCALL xmlRegFreeRegexp(xmlRegexpPtr regexp); +XMLPUBFUN int XMLCALL + xmlRegexpExec (xmlRegexpPtr comp, + const xmlChar *value); +XMLPUBFUN void XMLCALL + xmlRegexpPrint (FILE *output, + xmlRegexpPtr regexp); +XMLPUBFUN int XMLCALL + xmlRegexpIsDeterminist(xmlRegexpPtr comp); + +/** + * xmlRegExecCallbacks: + * @exec: the regular expression context + * @token: the current token string + * @transdata: transition data + * @inputdata: input data + * + * Callback function when doing a transition in the automata + */ +typedef void (*xmlRegExecCallbacks) (xmlRegExecCtxtPtr exec, + const xmlChar *token, + void *transdata, + void *inputdata); + +/* + * The progressive API + */ +XMLPUBFUN xmlRegExecCtxtPtr XMLCALL + xmlRegNewExecCtxt (xmlRegexpPtr comp, + xmlRegExecCallbacks callback, + void *data); +XMLPUBFUN void XMLCALL + xmlRegFreeExecCtxt (xmlRegExecCtxtPtr exec); +XMLPUBFUN int XMLCALL + xmlRegExecPushString(xmlRegExecCtxtPtr exec, + const xmlChar *value, + void *data); +XMLPUBFUN int XMLCALL + xmlRegExecPushString2(xmlRegExecCtxtPtr exec, + const xmlChar *value, + const xmlChar *value2, + void *data); + +XMLPUBFUN int XMLCALL + xmlRegExecNextValues(xmlRegExecCtxtPtr exec, + int *nbval, + int *nbneg, + xmlChar **values, + int *terminal); +XMLPUBFUN int XMLCALL + xmlRegExecErrInfo (xmlRegExecCtxtPtr exec, + const xmlChar **string, + int *nbval, + int *nbneg, + xmlChar **values, + int *terminal); +#ifdef LIBXML_EXPR_ENABLED +/* + * Formal regular expression handling + * Its goal is to do some formal work on content models + */ + +/* expressions are used within a context */ +typedef struct _xmlExpCtxt xmlExpCtxt; +typedef xmlExpCtxt *xmlExpCtxtPtr; + +XMLPUBFUN void XMLCALL + xmlExpFreeCtxt (xmlExpCtxtPtr ctxt); +XMLPUBFUN xmlExpCtxtPtr XMLCALL + xmlExpNewCtxt (int maxNodes, + xmlDictPtr dict); + +XMLPUBFUN int XMLCALL + xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt); + +/* Expressions are trees but the tree is opaque */ +typedef struct _xmlExpNode xmlExpNode; +typedef xmlExpNode *xmlExpNodePtr; + +typedef enum { + XML_EXP_EMPTY = 0, + XML_EXP_FORBID = 1, + XML_EXP_ATOM = 2, + XML_EXP_SEQ = 3, + XML_EXP_OR = 4, + XML_EXP_COUNT = 5 +} xmlExpNodeType; + +/* + * 2 core expressions shared by all for the empty language set + * and for the set with just the empty token + */ +XMLPUBVAR xmlExpNodePtr forbiddenExp; +XMLPUBVAR xmlExpNodePtr emptyExp; + +/* + * Expressions are reference counted internally + */ +XMLPUBFUN void XMLCALL + xmlExpFree (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr); +XMLPUBFUN void XMLCALL + xmlExpRef (xmlExpNodePtr expr); + +/* + * constructors can be either manual or from a string + */ +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpParse (xmlExpCtxtPtr ctxt, + const char *expr); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewAtom (xmlExpCtxtPtr ctxt, + const xmlChar *name, + int len); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewOr (xmlExpCtxtPtr ctxt, + xmlExpNodePtr left, + xmlExpNodePtr right); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewSeq (xmlExpCtxtPtr ctxt, + xmlExpNodePtr left, + xmlExpNodePtr right); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewRange (xmlExpCtxtPtr ctxt, + xmlExpNodePtr subset, + int min, + int max); +/* + * The really interesting APIs + */ +XMLPUBFUN int XMLCALL + xmlExpIsNillable(xmlExpNodePtr expr); +XMLPUBFUN int XMLCALL + xmlExpMaxToken (xmlExpNodePtr expr); +XMLPUBFUN int XMLCALL + xmlExpGetLanguage(xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar**langList, + int len); +XMLPUBFUN int XMLCALL + xmlExpGetStart (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar**tokList, + int len); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpStringDerive(xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar *str, + int len); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpExpDerive (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + xmlExpNodePtr sub); +XMLPUBFUN int XMLCALL + xmlExpSubsume (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + xmlExpNodePtr sub); +XMLPUBFUN void XMLCALL + xmlExpDump (xmlBufferPtr buf, + xmlExpNodePtr expr); +#endif /* LIBXML_EXPR_ENABLED */ +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /*__XML_REGEXP_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlsave.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlsave.h new file mode 100644 index 0000000..fb329b2 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlsave.h @@ -0,0 +1,88 @@ +/* + * Summary: the XML document serializer + * Description: API to save document or subtree of document + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLSAVE_H__ +#define __XML_XMLSAVE_H__ + +#include +#include +#include +#include + +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlSaveOption: + * + * This is the set of XML save options that can be passed down + * to the xmlSaveToFd() and similar calls. + */ +typedef enum { + XML_SAVE_FORMAT = 1<<0, /* format save output */ + XML_SAVE_NO_DECL = 1<<1, /* drop the xml declaration */ + XML_SAVE_NO_EMPTY = 1<<2, /* no empty tags */ + XML_SAVE_NO_XHTML = 1<<3, /* disable XHTML1 specific rules */ + XML_SAVE_XHTML = 1<<4, /* force XHTML1 specific rules */ + XML_SAVE_AS_XML = 1<<5, /* force XML serialization on HTML doc */ + XML_SAVE_AS_HTML = 1<<6, /* force HTML serialization on XML doc */ + XML_SAVE_WSNONSIG = 1<<7 /* format with non-significant whitespace */ +} xmlSaveOption; + + +typedef struct _xmlSaveCtxt xmlSaveCtxt; +typedef xmlSaveCtxt *xmlSaveCtxtPtr; + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToFd (int fd, + const char *encoding, + int options); +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToFilename (const char *filename, + const char *encoding, + int options); + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToBuffer (xmlBufferPtr buffer, + const char *encoding, + int options); + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + const char *encoding, + int options); + +XMLPUBFUN long XMLCALL + xmlSaveDoc (xmlSaveCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN long XMLCALL + xmlSaveTree (xmlSaveCtxtPtr ctxt, + xmlNodePtr node); + +XMLPUBFUN int XMLCALL + xmlSaveFlush (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSaveClose (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSaveSetEscape (xmlSaveCtxtPtr ctxt, + xmlCharEncodingOutputFunc escape); +XMLPUBFUN int XMLCALL + xmlSaveSetAttrEscape (xmlSaveCtxtPtr ctxt, + xmlCharEncodingOutputFunc escape); +#ifdef __cplusplus +} +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* __XML_XMLSAVE_H__ */ + + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlschemas.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlschemas.h new file mode 100644 index 0000000..97930c7 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlschemas.h @@ -0,0 +1,246 @@ +/* + * Summary: incomplete XML Schemas structure implementation + * Description: interface to the XML Schemas handling and schema validity + * checking, it is incomplete right now. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_H__ +#define __XML_SCHEMA_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This error codes are obsolete; not used any more. + */ +typedef enum { + XML_SCHEMAS_ERR_OK = 0, + XML_SCHEMAS_ERR_NOROOT = 1, + XML_SCHEMAS_ERR_UNDECLAREDELEM, + XML_SCHEMAS_ERR_NOTTOPLEVEL, + XML_SCHEMAS_ERR_MISSING, + XML_SCHEMAS_ERR_WRONGELEM, + XML_SCHEMAS_ERR_NOTYPE, + XML_SCHEMAS_ERR_NOROLLBACK, + XML_SCHEMAS_ERR_ISABSTRACT, + XML_SCHEMAS_ERR_NOTEMPTY, + XML_SCHEMAS_ERR_ELEMCONT, + XML_SCHEMAS_ERR_HAVEDEFAULT, + XML_SCHEMAS_ERR_NOTNILLABLE, + XML_SCHEMAS_ERR_EXTRACONTENT, + XML_SCHEMAS_ERR_INVALIDATTR, + XML_SCHEMAS_ERR_INVALIDELEM, + XML_SCHEMAS_ERR_NOTDETERMINIST, + XML_SCHEMAS_ERR_CONSTRUCT, + XML_SCHEMAS_ERR_INTERNAL, + XML_SCHEMAS_ERR_NOTSIMPLE, + XML_SCHEMAS_ERR_ATTRUNKNOWN, + XML_SCHEMAS_ERR_ATTRINVALID, + XML_SCHEMAS_ERR_VALUE, + XML_SCHEMAS_ERR_FACET, + XML_SCHEMAS_ERR_, + XML_SCHEMAS_ERR_XXX +} xmlSchemaValidError; + +/* +* ATTENTION: Change xmlSchemaSetValidOptions's check +* for invalid values, if adding to the validation +* options below. +*/ +/** + * xmlSchemaValidOption: + * + * This is the set of XML Schema validation options. + */ +typedef enum { + XML_SCHEMA_VAL_VC_I_CREATE = 1<<0 + /* Default/fixed: create an attribute node + * or an element's text node on the instance. + */ +} xmlSchemaValidOption; + +/* + XML_SCHEMA_VAL_XSI_ASSEMBLE = 1<<1, + * assemble schemata using + * xsi:schemaLocation and + * xsi:noNamespaceSchemaLocation +*/ + +/** + * The schemas related types are kept internal + */ +typedef struct _xmlSchema xmlSchema; +typedef xmlSchema *xmlSchemaPtr; + +/** + * xmlSchemaValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from an XSD validation + */ +typedef void (XMLCDECL *xmlSchemaValidityErrorFunc) + (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlSchemaValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from an XSD validation + */ +typedef void (XMLCDECL *xmlSchemaValidityWarningFunc) + (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * A schemas validation context + */ +typedef struct _xmlSchemaParserCtxt xmlSchemaParserCtxt; +typedef xmlSchemaParserCtxt *xmlSchemaParserCtxtPtr; + +typedef struct _xmlSchemaValidCtxt xmlSchemaValidCtxt; +typedef xmlSchemaValidCtxt *xmlSchemaValidCtxtPtr; + +/** + * xmlSchemaValidityLocatorFunc: + * @ctx: user provided context + * @file: returned file information + * @line: returned line information + * + * A schemas validation locator, a callback called by the validator. + * This is used when file or node informations are not available + * to find out what file and line number are affected + * + * Returns: 0 in case of success and -1 in case of error + */ + +typedef int (XMLCDECL *xmlSchemaValidityLocatorFunc) (void *ctx, + const char **file, unsigned long *line); + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL + xmlSchemaNewParserCtxt (const char *URL); +XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL + xmlSchemaNewMemParserCtxt (const char *buffer, + int size); +XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL + xmlSchemaNewDocParserCtxt (xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSchemaFreeParserCtxt (xmlSchemaParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlSchemaSetParserErrors (xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, + void *ctx); +XMLPUBFUN void XMLCALL + xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchemaGetParserErrors(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc * err, + xmlSchemaValidityWarningFunc * warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchemaIsValid (xmlSchemaValidCtxtPtr ctxt); + +XMLPUBFUN xmlSchemaPtr XMLCALL + xmlSchemaParse (xmlSchemaParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlSchemaFree (xmlSchemaPtr schema); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlSchemaDump (FILE *output, + xmlSchemaPtr schema); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * Interfaces for validating + */ +XMLPUBFUN void XMLCALL + xmlSchemaSetValidErrors (xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, + void *ctx); +XMLPUBFUN void XMLCALL + xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchemaGetValidErrors (xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc *err, + xmlSchemaValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchemaSetValidOptions (xmlSchemaValidCtxtPtr ctxt, + int options); +XMLPUBFUN void XMLCALL + xmlSchemaValidateSetFilename(xmlSchemaValidCtxtPtr vctxt, + const char *filename); +XMLPUBFUN int XMLCALL + xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt); + +XMLPUBFUN xmlSchemaValidCtxtPtr XMLCALL + xmlSchemaNewValidCtxt (xmlSchemaPtr schema); +XMLPUBFUN void XMLCALL + xmlSchemaFreeValidCtxt (xmlSchemaValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSchemaValidateDoc (xmlSchemaValidCtxtPtr ctxt, + xmlDocPtr instance); +XMLPUBFUN int XMLCALL + xmlSchemaValidateOneElement (xmlSchemaValidCtxtPtr ctxt, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlSchemaValidateStream (xmlSchemaValidCtxtPtr ctxt, + xmlParserInputBufferPtr input, + xmlCharEncoding enc, + xmlSAXHandlerPtr sax, + void *user_data); +XMLPUBFUN int XMLCALL + xmlSchemaValidateFile (xmlSchemaValidCtxtPtr ctxt, + const char * filename, + int options); + +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt); + +/* + * Interface to insert Schemas SAX validation in a SAX stream + */ +typedef struct _xmlSchemaSAXPlug xmlSchemaSAXPlugStruct; +typedef xmlSchemaSAXPlugStruct *xmlSchemaSAXPlugPtr; + +XMLPUBFUN xmlSchemaSAXPlugPtr XMLCALL + xmlSchemaSAXPlug (xmlSchemaValidCtxtPtr ctxt, + xmlSAXHandlerPtr *sax, + void **user_data); +XMLPUBFUN int XMLCALL + xmlSchemaSAXUnplug (xmlSchemaSAXPlugPtr plug); + + +XMLPUBFUN void XMLCALL + xmlSchemaValidateSetLocator (xmlSchemaValidCtxtPtr vctxt, + xmlSchemaValidityLocatorFunc f, + void *ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlschemastypes.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlschemastypes.h new file mode 100644 index 0000000..35d48d4 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlschemastypes.h @@ -0,0 +1,151 @@ +/* + * Summary: implementation of XML Schema Datatypes + * Description: module providing the XML Schema Datatypes implementation + * both definition and validity checking + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_TYPES_H__ +#define __XML_SCHEMA_TYPES_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMA_WHITESPACE_UNKNOWN = 0, + XML_SCHEMA_WHITESPACE_PRESERVE = 1, + XML_SCHEMA_WHITESPACE_REPLACE = 2, + XML_SCHEMA_WHITESPACE_COLLAPSE = 3 +} xmlSchemaWhitespaceValueType; + +XMLPUBFUN void XMLCALL + xmlSchemaInitTypes (void); +XMLPUBFUN void XMLCALL + xmlSchemaCleanupTypes (void); +XMLPUBFUN xmlSchemaTypePtr XMLCALL + xmlSchemaGetPredefinedType (const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int XMLCALL + xmlSchemaValidatePredefinedType (xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val); +XMLPUBFUN int XMLCALL + xmlSchemaValPredefTypeNode (xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val, + xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlSchemaValidateFacet (xmlSchemaTypePtr base, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val); +XMLPUBFUN int XMLCALL + xmlSchemaValidateFacetWhtsp (xmlSchemaFacetPtr facet, + xmlSchemaWhitespaceValueType fws, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN void XMLCALL + xmlSchemaFreeValue (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaFacetPtr XMLCALL + xmlSchemaNewFacet (void); +XMLPUBFUN int XMLCALL + xmlSchemaCheckFacet (xmlSchemaFacetPtr facet, + xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr ctxt, + const xmlChar *name); +XMLPUBFUN void XMLCALL + xmlSchemaFreeFacet (xmlSchemaFacetPtr facet); +XMLPUBFUN int XMLCALL + xmlSchemaCompareValues (xmlSchemaValPtr x, + xmlSchemaValPtr y); +XMLPUBFUN xmlSchemaTypePtr XMLCALL + xmlSchemaGetBuiltInListSimpleTypeItemType (xmlSchemaTypePtr type); +XMLPUBFUN int XMLCALL + xmlSchemaValidateListSimpleTypeFacet (xmlSchemaFacetPtr facet, + const xmlChar *value, + unsigned long actualLen, + unsigned long *expectedLen); +XMLPUBFUN xmlSchemaTypePtr XMLCALL + xmlSchemaGetBuiltInType (xmlSchemaValType type); +XMLPUBFUN int XMLCALL + xmlSchemaIsBuiltInTypeFacet (xmlSchemaTypePtr type, + int facetType); +XMLPUBFUN xmlChar * XMLCALL + xmlSchemaCollapseString (const xmlChar *value); +XMLPUBFUN xmlChar * XMLCALL + xmlSchemaWhiteSpaceReplace (const xmlChar *value); +XMLPUBFUN unsigned long XMLCALL + xmlSchemaGetFacetValueAsULong (xmlSchemaFacetPtr facet); +XMLPUBFUN int XMLCALL + xmlSchemaValidateLengthFacet (xmlSchemaTypePtr type, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length); +XMLPUBFUN int XMLCALL + xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN int XMLCALL + xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val, + xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlSchemaGetCanonValue (xmlSchemaValPtr val, + const xmlChar **retValue); +XMLPUBFUN int XMLCALL + xmlSchemaGetCanonValueWhtsp (xmlSchemaValPtr val, + const xmlChar **retValue, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN int XMLCALL + xmlSchemaValueAppend (xmlSchemaValPtr prev, + xmlSchemaValPtr cur); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaValueGetNext (xmlSchemaValPtr cur); +XMLPUBFUN const xmlChar * XMLCALL + xmlSchemaValueGetAsString (xmlSchemaValPtr val); +XMLPUBFUN int XMLCALL + xmlSchemaValueGetAsBoolean (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaNewStringValue (xmlSchemaValType type, + const xmlChar *value); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaNewNOTATIONValue (const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaNewQNameValue (const xmlChar *namespaceName, + const xmlChar *localName); +XMLPUBFUN int XMLCALL + xmlSchemaCompareValuesWhtsp (xmlSchemaValPtr x, + xmlSchemaWhitespaceValueType xws, + xmlSchemaValPtr y, + xmlSchemaWhitespaceValueType yws); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaCopyValue (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaValType XMLCALL + xmlSchemaGetValType (xmlSchemaValPtr val); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_TYPES_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlstring.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlstring.h new file mode 100644 index 0000000..2036236 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlstring.h @@ -0,0 +1,140 @@ +/* + * Summary: set of routines to process strings + * Description: type and interfaces needed for the internal string handling + * of the library, especially UTF8 processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_STRING_H__ +#define __XML_STRING_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlChar: + * + * This is a basic byte in an UTF-8 encoded string. + * It's unsigned allowing to pinpoint case where char * are assigned + * to xmlChar * (possibly making serialization back impossible). + */ +typedef unsigned char xmlChar; + +/** + * BAD_CAST: + * + * Macro to cast a string to an xmlChar * when one know its safe. + */ +#define BAD_CAST (xmlChar *) + +/* + * xmlChar handling + */ +XMLPUBFUN xmlChar * XMLCALL + xmlStrdup (const xmlChar *cur); +XMLPUBFUN xmlChar * XMLCALL + xmlStrndup (const xmlChar *cur, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlCharStrndup (const char *cur, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlCharStrdup (const char *cur); +XMLPUBFUN xmlChar * XMLCALL + xmlStrsub (const xmlChar *str, + int start, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlStrchr (const xmlChar *str, + xmlChar val); +XMLPUBFUN const xmlChar * XMLCALL + xmlStrstr (const xmlChar *str, + const xmlChar *val); +XMLPUBFUN const xmlChar * XMLCALL + xmlStrcasestr (const xmlChar *str, + const xmlChar *val); +XMLPUBFUN int XMLCALL + xmlStrcmp (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int XMLCALL + xmlStrncmp (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int XMLCALL + xmlStrcasecmp (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int XMLCALL + xmlStrncasecmp (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int XMLCALL + xmlStrEqual (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int XMLCALL + xmlStrQEqual (const xmlChar *pref, + const xmlChar *name, + const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlStrlen (const xmlChar *str); +XMLPUBFUN xmlChar * XMLCALL + xmlStrcat (xmlChar *cur, + const xmlChar *add); +XMLPUBFUN xmlChar * XMLCALL + xmlStrncat (xmlChar *cur, + const xmlChar *add, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlStrncatNew (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int XMLCALL + xmlStrPrintf (xmlChar *buf, + int len, + const xmlChar *msg, + ...); +XMLPUBFUN int XMLCALL + xmlStrVPrintf (xmlChar *buf, + int len, + const xmlChar *msg, + va_list ap); + +XMLPUBFUN int XMLCALL + xmlGetUTF8Char (const unsigned char *utf, + int *len); +XMLPUBFUN int XMLCALL + xmlCheckUTF8 (const unsigned char *utf); +XMLPUBFUN int XMLCALL + xmlUTF8Strsize (const xmlChar *utf, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlUTF8Strndup (const xmlChar *utf, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlUTF8Strpos (const xmlChar *utf, + int pos); +XMLPUBFUN int XMLCALL + xmlUTF8Strloc (const xmlChar *utf, + const xmlChar *utfchar); +XMLPUBFUN xmlChar * XMLCALL + xmlUTF8Strsub (const xmlChar *utf, + int start, + int len); +XMLPUBFUN int XMLCALL + xmlUTF8Strlen (const xmlChar *utf); +XMLPUBFUN int XMLCALL + xmlUTF8Size (const xmlChar *utf); +XMLPUBFUN int XMLCALL + xmlUTF8Charcmp (const xmlChar *utf1, + const xmlChar *utf2); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_STRING_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlunicode.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlunicode.h new file mode 100644 index 0000000..01ac8b6 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlunicode.h @@ -0,0 +1,202 @@ +/* + * Summary: Unicode character APIs + * Description: API for the Unicode character APIs + * + * This file is automatically generated from the + * UCS description files of the Unicode Character Database + * http://www.unicode.org/Public/4.0-Update1/UCD-4.0.1.html + * using the genUnicode.py Python script. + * + * Generation date: Mon Mar 27 11:09:52 2006 + * Sources: Blocks-4.0.1.txt UnicodeData-4.0.1.txt + * Author: Daniel Veillard + */ + +#ifndef __XML_UNICODE_H__ +#define __XML_UNICODE_H__ + +#include + +#ifdef LIBXML_UNICODE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN int XMLCALL xmlUCSIsAegeanNumbers (int code); +XMLPUBFUN int XMLCALL xmlUCSIsAlphabeticPresentationForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArabic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArabicPresentationFormsA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArabicPresentationFormsB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArmenian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArrows (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBasicLatin (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBengali (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBlockElements (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBopomofo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBopomofoExtended (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBoxDrawing (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBraillePatterns (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBuhid (int code); +XMLPUBFUN int XMLCALL xmlUCSIsByzantineMusicalSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibility (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibilityForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibilityIdeographs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibilityIdeographsSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKRadicalsSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKSymbolsandPunctuation (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKUnifiedIdeographs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKUnifiedIdeographsExtensionA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKUnifiedIdeographsExtensionB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCherokee (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningDiacriticalMarks (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningDiacriticalMarksforSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningHalfMarks (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningMarksforSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsControlPictures (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCurrencySymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCypriotSyllabary (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCyrillic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCyrillicSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsDeseret (int code); +XMLPUBFUN int XMLCALL xmlUCSIsDevanagari (int code); +XMLPUBFUN int XMLCALL xmlUCSIsDingbats (int code); +XMLPUBFUN int XMLCALL xmlUCSIsEnclosedAlphanumerics (int code); +XMLPUBFUN int XMLCALL xmlUCSIsEnclosedCJKLettersandMonths (int code); +XMLPUBFUN int XMLCALL xmlUCSIsEthiopic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGeneralPunctuation (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGeometricShapes (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGeorgian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGothic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGreek (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGreekExtended (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGreekandCoptic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGujarati (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGurmukhi (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHalfwidthandFullwidthForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHangulCompatibilityJamo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHangulJamo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHangulSyllables (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHanunoo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHebrew (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHighPrivateUseSurrogates (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHighSurrogates (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHiragana (int code); +XMLPUBFUN int XMLCALL xmlUCSIsIPAExtensions (int code); +XMLPUBFUN int XMLCALL xmlUCSIsIdeographicDescriptionCharacters (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKanbun (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKangxiRadicals (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKannada (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKatakana (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKatakanaPhoneticExtensions (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKhmer (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKhmerSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLao (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatin1Supplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatinExtendedA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatinExtendedB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatinExtendedAdditional (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLetterlikeSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLimbu (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLinearBIdeograms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLinearBSyllabary (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLowSurrogates (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMalayalam (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMathematicalAlphanumericSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMathematicalOperators (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousMathematicalSymbolsA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousMathematicalSymbolsB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousSymbolsandArrows (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousTechnical (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMongolian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMusicalSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMyanmar (int code); +XMLPUBFUN int XMLCALL xmlUCSIsNumberForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOgham (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOldItalic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOpticalCharacterRecognition (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOriya (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOsmanya (int code); +XMLPUBFUN int XMLCALL xmlUCSIsPhoneticExtensions (int code); +XMLPUBFUN int XMLCALL xmlUCSIsPrivateUse (int code); +XMLPUBFUN int XMLCALL xmlUCSIsPrivateUseArea (int code); +XMLPUBFUN int XMLCALL xmlUCSIsRunic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsShavian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSinhala (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSmallFormVariants (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSpacingModifierLetters (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSpecials (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSuperscriptsandSubscripts (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementalArrowsA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementalArrowsB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementalMathematicalOperators (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementaryPrivateUseAreaA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementaryPrivateUseAreaB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSyriac (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTagalog (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTagbanwa (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTags (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTaiLe (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTaiXuanJingSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTamil (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTelugu (int code); +XMLPUBFUN int XMLCALL xmlUCSIsThaana (int code); +XMLPUBFUN int XMLCALL xmlUCSIsThai (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTibetan (int code); +XMLPUBFUN int XMLCALL xmlUCSIsUgaritic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsUnifiedCanadianAboriginalSyllabics (int code); +XMLPUBFUN int XMLCALL xmlUCSIsVariationSelectors (int code); +XMLPUBFUN int XMLCALL xmlUCSIsVariationSelectorsSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsYiRadicals (int code); +XMLPUBFUN int XMLCALL xmlUCSIsYiSyllables (int code); +XMLPUBFUN int XMLCALL xmlUCSIsYijingHexagramSymbols (int code); + +XMLPUBFUN int XMLCALL xmlUCSIsBlock (int code, const char *block); + +XMLPUBFUN int XMLCALL xmlUCSIsCatC (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCf (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatL (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLl (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLm (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLt (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLu (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatM (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatMc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatMe (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatMn (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatN (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatNd (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatNl (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatNo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatP (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPd (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPe (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPf (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPi (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatS (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSk (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSm (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZ (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZl (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZp (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZs (int code); + +XMLPUBFUN int XMLCALL xmlUCSIsCat (int code, const char *cat); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_UNICODE_ENABLED */ + +#endif /* __XML_UNICODE_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlversion.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlversion.h new file mode 100644 index 0000000..49a42bd --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlversion.h @@ -0,0 +1,489 @@ +/* + * Summary: compile-time version informations + * Description: compile-time version informations for the XML library + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_VERSION_H__ +#define __XML_VERSION_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +XMLPUBFUN void XMLCALL xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ + +/** + * LIBXML_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXML_DOTTED_VERSION "2.9.4" + +/** + * LIBXML_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXML_VERSION 20904 + +/** + * LIBXML_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXML_VERSION_STRING "20904" + +/** + * LIBXML_VERSION_EXTRA: + * + * extra version information, used to show a CVS compilation + */ +#define LIBXML_VERSION_EXTRA "" + +/** + * LIBXML_TEST_VERSION: + * + * Macro to check that the libxml version in use is compatible with + * the version the software has been compiled against + */ +#define LIBXML_TEST_VERSION xmlCheckVersion(20904); + +#ifndef VMS +#if 0 +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO +#else +/** + * WITHOUT_TRIO: + * + * defined if the trio support should not be configured in + */ +#define WITHOUT_TRIO +#endif +#else /* VMS */ +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO 1 +#endif /* VMS */ + +/** + * LIBXML_THREAD_ENABLED: + * + * Whether the thread support is configured in + */ +#if 1 +#if defined(_REENTRANT) || defined(__MT__) || \ + (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0 >= 199506L)) +#define LIBXML_THREAD_ENABLED +#endif +#endif + +/** + * LIBXML_THREAD_ALLOC_ENABLED: + * + * Whether the allocation hooks are per-thread + */ +#if 0 +#define LIBXML_THREAD_ALLOC_ENABLED +#endif + +/** + * LIBXML_TREE_ENABLED: + * + * Whether the DOM like tree manipulation API support is configured in + */ +#if 1 +#define LIBXML_TREE_ENABLED +#endif + +/** + * LIBXML_OUTPUT_ENABLED: + * + * Whether the serialization/saving support is configured in + */ +#if 1 +#define LIBXML_OUTPUT_ENABLED +#endif + +/** + * LIBXML_PUSH_ENABLED: + * + * Whether the push parsing interfaces are configured in + */ +#if 1 +#define LIBXML_PUSH_ENABLED +#endif + +/** + * LIBXML_READER_ENABLED: + * + * Whether the xmlReader parsing interface is configured in + */ +#if 1 +#define LIBXML_READER_ENABLED +#endif + +/** + * LIBXML_PATTERN_ENABLED: + * + * Whether the xmlPattern node selection interface is configured in + */ +#if 1 +#define LIBXML_PATTERN_ENABLED +#endif + +/** + * LIBXML_WRITER_ENABLED: + * + * Whether the xmlWriter saving interface is configured in + */ +#if 1 +#define LIBXML_WRITER_ENABLED +#endif + +/** + * LIBXML_SAX1_ENABLED: + * + * Whether the older SAX1 interface is configured in + */ +#if 1 +#define LIBXML_SAX1_ENABLED +#endif + +/** + * LIBXML_FTP_ENABLED: + * + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#endif + +/** + * LIBXML_HTTP_ENABLED: + * + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#endif + +/** + * LIBXML_VALID_ENABLED: + * + * Whether the DTD validation support is configured in + */ +#if 1 +#define LIBXML_VALID_ENABLED +#endif + +/** + * LIBXML_HTML_ENABLED: + * + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#endif + +/** + * LIBXML_LEGACY_ENABLED: + * + * Whether the deprecated APIs are compiled in for compatibility + */ +#if 1 +#define LIBXML_LEGACY_ENABLED +#endif + +/** + * LIBXML_C14N_ENABLED: + * + * Whether the Canonicalization support is configured in + */ +#if 1 +#define LIBXML_C14N_ENABLED +#endif + +/** + * LIBXML_CATALOG_ENABLED: + * + * Whether the Catalog support is configured in + */ +#if 1 +#define LIBXML_CATALOG_ENABLED +#endif + +/** + * LIBXML_DOCB_ENABLED: + * + * Whether the SGML Docbook support is configured in + */ +#if 1 +#define LIBXML_DOCB_ENABLED +#endif + +/** + * LIBXML_XPATH_ENABLED: + * + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#endif + +/** + * LIBXML_XPTR_ENABLED: + * + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#endif + +/** + * LIBXML_XINCLUDE_ENABLED: + * + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#endif + +/** + * LIBXML_ICONV_ENABLED: + * + * Whether iconv support is available + */ +#if 0 +#define LIBXML_ICONV_ENABLED +#endif + +/** + * LIBXML_ICU_ENABLED: + * + * Whether icu support is available + */ +#if 0 +#define LIBXML_ICU_ENABLED +#endif + +/** + * LIBXML_ISO8859X_ENABLED: + * + * Whether ISO-8859-* support is made available in case iconv is not + */ +#if 0 +#define LIBXML_ISO8859X_ENABLED +#endif + +/** + * LIBXML_DEBUG_ENABLED: + * + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#endif + +/** + * DEBUG_MEMORY_LOCATION: + * + * Whether the memory debugging is configured in + */ +#if 0 +#define DEBUG_MEMORY_LOCATION +#endif + +/** + * LIBXML_DEBUG_RUNTIME: + * + * Whether the runtime debugging is configured in + */ +#if 0 +#define LIBXML_DEBUG_RUNTIME +#endif + +/** + * LIBXML_UNICODE_ENABLED: + * + * Whether the Unicode related interfaces are compiled in + */ +#if 1 +#define LIBXML_UNICODE_ENABLED +#endif + +/** + * LIBXML_REGEXP_ENABLED: + * + * Whether the regular expressions interfaces are compiled in + */ +#if 1 +#define LIBXML_REGEXP_ENABLED +#endif + +/** + * LIBXML_AUTOMATA_ENABLED: + * + * Whether the automata interfaces are compiled in + */ +#if 1 +#define LIBXML_AUTOMATA_ENABLED +#endif + +/** + * LIBXML_EXPR_ENABLED: + * + * Whether the formal expressions interfaces are compiled in + */ +#if 1 +#define LIBXML_EXPR_ENABLED +#endif + +/** + * LIBXML_SCHEMAS_ENABLED: + * + * Whether the Schemas validation interfaces are compiled in + */ +#if 1 +#define LIBXML_SCHEMAS_ENABLED +#endif + +/** + * LIBXML_SCHEMATRON_ENABLED: + * + * Whether the Schematron validation interfaces are compiled in + */ +#if 1 +#define LIBXML_SCHEMATRON_ENABLED +#endif + +/** + * LIBXML_MODULES_ENABLED: + * + * Whether the module interfaces are compiled in + */ +#if 1 +#define LIBXML_MODULES_ENABLED +/** + * LIBXML_MODULE_EXTENSION: + * + * the string suffix used by dynamic modules (usually shared libraries) + */ +#define LIBXML_MODULE_EXTENSION ".dll" +#endif + +/** + * LIBXML_ZLIB_ENABLED: + * + * Whether the Zlib support is compiled in + */ +#if 0 +#define LIBXML_ZLIB_ENABLED +#endif + +/** + * LIBXML_LZMA_ENABLED: + * + * Whether the Lzma support is compiled in + */ +#if 0 +#define LIBXML_LZMA_ENABLED +#endif + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ + +#ifndef ATTRIBUTE_UNUSED +# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) +# define ATTRIBUTE_UNUSED __attribute__((unused)) +# else +# define ATTRIBUTE_UNUSED +# endif +#endif + +/** + * LIBXML_ATTR_ALLOC_SIZE: + * + * Macro used to indicate to GCC this is an allocator function + */ + +#ifndef LIBXML_ATTR_ALLOC_SIZE +# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))) +# define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) +# else +# define LIBXML_ATTR_ALLOC_SIZE(x) +# endif +#else +# define LIBXML_ATTR_ALLOC_SIZE(x) +#endif + +/** + * LIBXML_ATTR_FORMAT: + * + * Macro used to indicate to GCC the parameter are printf like + */ + +#ifndef LIBXML_ATTR_FORMAT +# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))) +# define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args))) +# else +# define LIBXML_ATTR_FORMAT(fmt,args) +# endif +#else +# define LIBXML_ATTR_FORMAT(fmt,args) +#endif + +#else /* ! __GNUC__ */ +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ +#define ATTRIBUTE_UNUSED +/** + * LIBXML_ATTR_ALLOC_SIZE: + * + * Macro used to indicate to GCC this is an allocator function + */ +#define LIBXML_ATTR_ALLOC_SIZE(x) +/** + * LIBXML_ATTR_FORMAT: + * + * Macro used to indicate to GCC the parameter are printf like + */ +#define LIBXML_ATTR_FORMAT(fmt,args) +#endif /* __GNUC__ */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif + + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlwin32version.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlwin32version.h new file mode 100644 index 0000000..9641241 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlwin32version.h @@ -0,0 +1,242 @@ +/* + * Summary: compile-time version informations on Windows + * Description: compile-time version informations for the XML library + * when compiled on the Windows platform + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_VERSION_H__ +#define __XML_VERSION_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +extern void xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ + +/** + * LIBXML_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXML_DOTTED_VERSION "2.4.26" + +/** + * LIBXML_VERSION: + * + * the version number: 1.2.3 value is 1002003 + */ +#define LIBXML_VERSION 20426 + +/** + * LIBXML_VERSION_STRING: + * + * the version number string, 1.2.3 value is "1002003" + */ +#define LIBXML_VERSION_STRING "20426" + +/** + * LIBXML_TEST_VERSION: + * + * Macro to check that the libxml version in use is compatible with + * the version the software has been compiled against + */ +#define LIBXML_TEST_VERSION xmlCheckVersion(20426); + +#if 0 +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO +#else +/** + * WITHOUT_TRIO: + * + * defined if the trio support should not be configured in + */ +#define WITHOUT_TRIO +#endif + +/** + * LIBXML_THREAD_ENABLED: + * + * Whether the thread support is configured in + */ +#if 0 +#define LIBXML_THREAD_ENABLED +#endif + +/** + * LIBXML_FTP_ENABLED: + * + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#endif + +/** + * LIBXML_HTTP_ENABLED: + * + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#endif + +/** + * LIBXML_HTML_ENABLED: + * + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#endif + +/** + * LIBXML_CATALOG_ENABLED: + * + * Whether the Catalog support is configured in + */ +#if 1 +#define LIBXML_CATALOG_ENABLED +#endif + +/** + * LIBXML_DOCB_ENABLED: + * + * Whether the SGML Docbook support is configured in + */ +#if 1 +#define LIBXML_DOCB_ENABLED +#endif + +/** + * LIBXML_XPATH_ENABLED: + * + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#endif + +/** + * LIBXML_XPTR_ENABLED: + * + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#endif + +/** + * LIBXML_C14N_ENABLED: + * + * Whether the Canonicalization support is configured in + */ +#if 0 +#define LIBXML_C14N_ENABLED +#endif + +/** + * LIBXML_XINCLUDE_ENABLED: + * + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#endif + +/** + * LIBXML_ICONV_ENABLED: + * + * Whether iconv support is available + */ +#if 0 +#define LIBXML_ICONV_ENABLED +#endif + +/** + * LIBXML_DEBUG_ENABLED: + * + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#endif + +/** + * DEBUG_MEMORY_LOCATION: + * + * Whether the memory debugging is configured in + */ +#if 0 +#define DEBUG_MEMORY_LOCATION +#endif + +/** + * LIBXML_DLL_IMPORT: + * + * Used on Windows (MS C compiler only) to declare a variable as + * imported from the library. This macro should be empty when compiling + * libxml itself. It should expand to __declspec(dllimport) + * when the client code includes this header, and that only if the client + * links dynamically against libxml. + * For this to work, we need three macros. One tells us which compiler is + * being used and luckily the compiler defines such a thing: _MSC_VER. The + * second macro tells us if we are compiling libxml or the client code and + * we define the macro IN_LIBXML on the compiler's command line for this + * purpose. The third macro, LIBXML_STATIC, must be defined by any client + * code which links against libxml statically. + */ +#ifndef LIBXML_DLL_IMPORT +#if defined(_MSC_VER) && !defined(IN_LIBXML) && !defined(LIBXML_STATIC) +#define LIBXML_DLL_IMPORT __declspec(dllimport) +#else +#define LIBXML_DLL_IMPORT +#endif +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + +/* + * #pragma comment(lib, "iconv.lib") + * + * pragma understood my MS compiler which enables a conditional link with + * iconv. + */ +#ifdef _MSC_VER +#if defined LIBXML_ICONV_ENABLED && !defined LIBXML2_COMPILING_MSCCDEF +#pragma comment(lib, "iconv.lib") +#endif +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlwriter.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlwriter.h new file mode 100644 index 0000000..dd5add3 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xmlwriter.h @@ -0,0 +1,488 @@ +/* + * Summary: text writing API for XML + * Description: text writing API for XML + * + * Copy: See Copyright for the status of this software. + * + * Author: Alfred Mickautsch + */ + +#ifndef __XML_XMLWRITER_H__ +#define __XML_XMLWRITER_H__ + +#include + +#ifdef LIBXML_WRITER_ENABLED + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _xmlTextWriter xmlTextWriter; + typedef xmlTextWriter *xmlTextWriterPtr; + +/* + * Constructors & Destructor + */ + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriter(xmlOutputBufferPtr out); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterFilename(const char *uri, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterMemory(xmlBufferPtr buf, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterPushParser(xmlParserCtxtPtr ctxt, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterDoc(xmlDocPtr * doc, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterTree(xmlDocPtr doc, xmlNodePtr node, + int compression); + XMLPUBFUN void XMLCALL xmlFreeTextWriter(xmlTextWriterPtr writer); + +/* + * Functions + */ + + +/* + * Document + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDocument(xmlTextWriterPtr writer, + const char *version, + const char *encoding, + const char *standalone); + XMLPUBFUN int XMLCALL xmlTextWriterEndDocument(xmlTextWriterPtr + writer); + +/* + * Comments + */ + XMLPUBFUN int XMLCALL xmlTextWriterStartComment(xmlTextWriterPtr + writer); + XMLPUBFUN int XMLCALL xmlTextWriterEndComment(xmlTextWriterPtr writer); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatComment(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatComment(xmlTextWriterPtr writer, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteComment(xmlTextWriterPtr + writer, + const xmlChar * + content); + +/* + * Elements + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartElement(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterStartElementNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * name, + const xmlChar * + namespaceURI); + XMLPUBFUN int XMLCALL xmlTextWriterEndElement(xmlTextWriterPtr writer); + XMLPUBFUN int XMLCALL xmlTextWriterFullEndElement(xmlTextWriterPtr + writer); + +/* + * Elements conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteElement(xmlTextWriterPtr + writer, + const xmlChar * name, + const xmlChar * + content); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteElementNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * name, + const xmlChar * + namespaceURI, + const xmlChar * + content); + +/* + * Text + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatRaw(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatRaw(xmlTextWriterPtr writer, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteRawLen(xmlTextWriterPtr writer, + const xmlChar * content, int len); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteRaw(xmlTextWriterPtr writer, + const xmlChar * content); + XMLPUBFUN int XMLCALL xmlTextWriterWriteFormatString(xmlTextWriterPtr + writer, + const char + *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL xmlTextWriterWriteVFormatString(xmlTextWriterPtr + writer, + const char + *format, + va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteString(xmlTextWriterPtr writer, + const xmlChar * + content); + XMLPUBFUN int XMLCALL xmlTextWriterWriteBase64(xmlTextWriterPtr writer, + const char *data, + int start, int len); + XMLPUBFUN int XMLCALL xmlTextWriterWriteBinHex(xmlTextWriterPtr writer, + const char *data, + int start, int len); + +/* + * Attributes + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartAttribute(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterStartAttributeNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * + name, + const xmlChar * + namespaceURI); + XMLPUBFUN int XMLCALL xmlTextWriterEndAttribute(xmlTextWriterPtr + writer); + +/* + * Attributes conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteAttribute(xmlTextWriterPtr + writer, + const xmlChar * name, + const xmlChar * + content); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteAttributeNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * + name, + const xmlChar * + namespaceURI, + const xmlChar * + content); + +/* + * PI's + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartPI(xmlTextWriterPtr writer, + const xmlChar * target); + XMLPUBFUN int XMLCALL xmlTextWriterEndPI(xmlTextWriterPtr writer); + +/* + * PI conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWritePI(xmlTextWriterPtr writer, + const xmlChar * target, + const xmlChar * content); + +/** + * xmlTextWriterWriteProcessingInstruction: + * + * This macro maps to xmlTextWriterWritePI + */ +#define xmlTextWriterWriteProcessingInstruction xmlTextWriterWritePI + +/* + * CDATA + */ + XMLPUBFUN int XMLCALL xmlTextWriterStartCDATA(xmlTextWriterPtr writer); + XMLPUBFUN int XMLCALL xmlTextWriterEndCDATA(xmlTextWriterPtr writer); + +/* + * CDATA conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatCDATA(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatCDATA(xmlTextWriterPtr writer, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteCDATA(xmlTextWriterPtr writer, + const xmlChar * content); + +/* + * DTD + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTD(xmlTextWriterPtr writer); + +/* + * DTD conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * subset); + +/** + * xmlTextWriterWriteDocType: + * + * this macro maps to xmlTextWriterWriteDTD + */ +#define xmlTextWriterWriteDocType xmlTextWriterWriteDTD + +/* + * DTD element definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTDElement(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTDElement(xmlTextWriterPtr + writer); + +/* + * DTD element definition conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDElement(xmlTextWriterPtr + writer, + const xmlChar * + name, + const xmlChar * + content); + +/* + * DTD attribute list definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTDAttlist(xmlTextWriterPtr + writer); + +/* + * DTD attribute list definition conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDAttlist(xmlTextWriterPtr + writer, + const xmlChar * + name, + const xmlChar * + content); + +/* + * DTD entity definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTDEntity(xmlTextWriterPtr writer, + int pe, const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTDEntity(xmlTextWriterPtr + writer); + +/* + * DTD entity definition conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(4,5); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(4,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * content); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDExternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * ndataid); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDExternalEntityContents(xmlTextWriterPtr + writer, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * + ndataid); + XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDEntity(xmlTextWriterPtr + writer, int pe, + const xmlChar * name, + const xmlChar * + pubid, + const xmlChar * + sysid, + const xmlChar * + ndataid, + const xmlChar * + content); + +/* + * DTD notation definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDNotation(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid); + +/* + * Indentation + */ + XMLPUBFUN int XMLCALL + xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent); + XMLPUBFUN int XMLCALL + xmlTextWriterSetIndentString(xmlTextWriterPtr writer, + const xmlChar * str); + + XMLPUBFUN int XMLCALL + xmlTextWriterSetQuoteChar(xmlTextWriterPtr writer, xmlChar quotechar); + + +/* + * misc + */ + XMLPUBFUN int XMLCALL xmlTextWriterFlush(xmlTextWriterPtr writer); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_WRITER_ENABLED */ + +#endif /* __XML_XMLWRITER_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpath.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpath.h new file mode 100644 index 0000000..d96776c --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpath.h @@ -0,0 +1,557 @@ +/* + * Summary: XML Path Language implementation + * Description: API for the XML Path Language implementation + * + * XML Path Language implementation + * XPath is a language for addressing parts of an XML document, + * designed to be used by both XSLT and XPointer + * http://www.w3.org/TR/xpath + * + * Implements + * W3C Recommendation 16 November 1999 + * http://www.w3.org/TR/1999/REC-xpath-19991116 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPATH_H__ +#define __XML_XPATH_H__ + +#include + +#ifdef LIBXML_XPATH_ENABLED + +#include +#include +#include +#endif /* LIBXML_XPATH_ENABLED */ + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef __cplusplus +extern "C" { +#endif +#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +#ifdef LIBXML_XPATH_ENABLED + +typedef struct _xmlXPathContext xmlXPathContext; +typedef xmlXPathContext *xmlXPathContextPtr; +typedef struct _xmlXPathParserContext xmlXPathParserContext; +typedef xmlXPathParserContext *xmlXPathParserContextPtr; + +/** + * The set of XPath error codes. + */ + +typedef enum { + XPATH_EXPRESSION_OK = 0, + XPATH_NUMBER_ERROR, + XPATH_UNFINISHED_LITERAL_ERROR, + XPATH_START_LITERAL_ERROR, + XPATH_VARIABLE_REF_ERROR, + XPATH_UNDEF_VARIABLE_ERROR, + XPATH_INVALID_PREDICATE_ERROR, + XPATH_EXPR_ERROR, + XPATH_UNCLOSED_ERROR, + XPATH_UNKNOWN_FUNC_ERROR, + XPATH_INVALID_OPERAND, + XPATH_INVALID_TYPE, + XPATH_INVALID_ARITY, + XPATH_INVALID_CTXT_SIZE, + XPATH_INVALID_CTXT_POSITION, + XPATH_MEMORY_ERROR, + XPTR_SYNTAX_ERROR, + XPTR_RESOURCE_ERROR, + XPTR_SUB_RESOURCE_ERROR, + XPATH_UNDEF_PREFIX_ERROR, + XPATH_ENCODING_ERROR, + XPATH_INVALID_CHAR_ERROR, + XPATH_INVALID_CTXT, + XPATH_STACK_ERROR, + XPATH_FORBID_VARIABLE_ERROR +} xmlXPathError; + +/* + * A node-set (an unordered collection of nodes without duplicates). + */ +typedef struct _xmlNodeSet xmlNodeSet; +typedef xmlNodeSet *xmlNodeSetPtr; +struct _xmlNodeSet { + int nodeNr; /* number of nodes in the set */ + int nodeMax; /* size of the array as allocated */ + xmlNodePtr *nodeTab; /* array of nodes in no particular order */ + /* @@ with_ns to check wether namespace nodes should be looked at @@ */ +}; + +/* + * An expression is evaluated to yield an object, which + * has one of the following four basic types: + * - node-set + * - boolean + * - number + * - string + * + * @@ XPointer will add more types ! + */ + +typedef enum { + XPATH_UNDEFINED = 0, + XPATH_NODESET = 1, + XPATH_BOOLEAN = 2, + XPATH_NUMBER = 3, + XPATH_STRING = 4, + XPATH_POINT = 5, + XPATH_RANGE = 6, + XPATH_LOCATIONSET = 7, + XPATH_USERS = 8, + XPATH_XSLT_TREE = 9 /* An XSLT value tree, non modifiable */ +} xmlXPathObjectType; + +typedef struct _xmlXPathObject xmlXPathObject; +typedef xmlXPathObject *xmlXPathObjectPtr; +struct _xmlXPathObject { + xmlXPathObjectType type; + xmlNodeSetPtr nodesetval; + int boolval; + double floatval; + xmlChar *stringval; + void *user; + int index; + void *user2; + int index2; +}; + +/** + * xmlXPathConvertFunc: + * @obj: an XPath object + * @type: the number of the target type + * + * A conversion function is associated to a type and used to cast + * the new type to primitive values. + * + * Returns -1 in case of error, 0 otherwise + */ +typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type); + +/* + * Extra type: a name and a conversion function. + */ + +typedef struct _xmlXPathType xmlXPathType; +typedef xmlXPathType *xmlXPathTypePtr; +struct _xmlXPathType { + const xmlChar *name; /* the type name */ + xmlXPathConvertFunc func; /* the conversion function */ +}; + +/* + * Extra variable: a name and a value. + */ + +typedef struct _xmlXPathVariable xmlXPathVariable; +typedef xmlXPathVariable *xmlXPathVariablePtr; +struct _xmlXPathVariable { + const xmlChar *name; /* the variable name */ + xmlXPathObjectPtr value; /* the value */ +}; + +/** + * xmlXPathEvalFunc: + * @ctxt: an XPath parser context + * @nargs: the number of arguments passed to the function + * + * An XPath evaluation function, the parameters are on the XPath context stack. + */ + +typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, + int nargs); + +/* + * Extra function: a name and a evaluation function. + */ + +typedef struct _xmlXPathFunct xmlXPathFunct; +typedef xmlXPathFunct *xmlXPathFuncPtr; +struct _xmlXPathFunct { + const xmlChar *name; /* the function name */ + xmlXPathEvalFunc func; /* the evaluation function */ +}; + +/** + * xmlXPathAxisFunc: + * @ctxt: the XPath interpreter context + * @cur: the previous node being explored on that axis + * + * An axis traversal function. To traverse an axis, the engine calls + * the first time with cur == NULL and repeat until the function returns + * NULL indicating the end of the axis traversal. + * + * Returns the next node in that axis or NULL if at the end of the axis. + */ + +typedef xmlXPathObjectPtr (*xmlXPathAxisFunc) (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr cur); + +/* + * Extra axis: a name and an axis function. + */ + +typedef struct _xmlXPathAxis xmlXPathAxis; +typedef xmlXPathAxis *xmlXPathAxisPtr; +struct _xmlXPathAxis { + const xmlChar *name; /* the axis name */ + xmlXPathAxisFunc func; /* the search function */ +}; + +/** + * xmlXPathFunction: + * @ctxt: the XPath interprestation context + * @nargs: the number of arguments + * + * An XPath function. + * The arguments (if any) are popped out from the context stack + * and the result is pushed on the stack. + */ + +typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); + +/* + * Function and Variable Lookup. + */ + +/** + * xmlXPathVariableLookupFunc: + * @ctxt: an XPath context + * @name: name of the variable + * @ns_uri: the namespace name hosting this variable + * + * Prototype for callbacks used to plug variable lookup in the XPath + * engine. + * + * Returns the XPath object value or NULL if not found. + */ +typedef xmlXPathObjectPtr (*xmlXPathVariableLookupFunc) (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/** + * xmlXPathFuncLookupFunc: + * @ctxt: an XPath context + * @name: name of the function + * @ns_uri: the namespace name hosting this function + * + * Prototype for callbacks used to plug function lookup in the XPath + * engine. + * + * Returns the XPath function or NULL if not found. + */ +typedef xmlXPathFunction (*xmlXPathFuncLookupFunc) (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/** + * xmlXPathFlags: + * Flags for XPath engine compilation and runtime + */ +/** + * XML_XPATH_CHECKNS: + * + * check namespaces at compilation + */ +#define XML_XPATH_CHECKNS (1<<0) +/** + * XML_XPATH_NOVAR: + * + * forbid variables in expression + */ +#define XML_XPATH_NOVAR (1<<1) + +/** + * xmlXPathContext: + * + * Expression evaluation occurs with respect to a context. + * he context consists of: + * - a node (the context node) + * - a node list (the context node list) + * - a set of variable bindings + * - a function library + * - the set of namespace declarations in scope for the expression + * Following the switch to hash tables, this need to be trimmed up at + * the next binary incompatible release. + * The node may be modified when the context is passed to libxml2 + * for an XPath evaluation so you may need to initialize it again + * before the next call. + */ + +struct _xmlXPathContext { + xmlDocPtr doc; /* The current document */ + xmlNodePtr node; /* The current node */ + + int nb_variables_unused; /* unused (hash table) */ + int max_variables_unused; /* unused (hash table) */ + xmlHashTablePtr varHash; /* Hash table of defined variables */ + + int nb_types; /* number of defined types */ + int max_types; /* max number of types */ + xmlXPathTypePtr types; /* Array of defined types */ + + int nb_funcs_unused; /* unused (hash table) */ + int max_funcs_unused; /* unused (hash table) */ + xmlHashTablePtr funcHash; /* Hash table of defined funcs */ + + int nb_axis; /* number of defined axis */ + int max_axis; /* max number of axis */ + xmlXPathAxisPtr axis; /* Array of defined axis */ + + /* the namespace nodes of the context node */ + xmlNsPtr *namespaces; /* Array of namespaces */ + int nsNr; /* number of namespace in scope */ + void *user; /* function to free */ + + /* extra variables */ + int contextSize; /* the context size */ + int proximityPosition; /* the proximity position */ + + /* extra stuff for XPointer */ + int xptr; /* is this an XPointer context? */ + xmlNodePtr here; /* for here() */ + xmlNodePtr origin; /* for origin() */ + + /* the set of namespace declarations in scope for the expression */ + xmlHashTablePtr nsHash; /* The namespaces hash table */ + xmlXPathVariableLookupFunc varLookupFunc;/* variable lookup func */ + void *varLookupData; /* variable lookup data */ + + /* Possibility to link in an extra item */ + void *extra; /* needed for XSLT */ + + /* The function name and URI when calling a function */ + const xmlChar *function; + const xmlChar *functionURI; + + /* function lookup function and data */ + xmlXPathFuncLookupFunc funcLookupFunc;/* function lookup func */ + void *funcLookupData; /* function lookup data */ + + /* temporary namespace lists kept for walking the namespace axis */ + xmlNsPtr *tmpNsList; /* Array of namespaces */ + int tmpNsNr; /* number of namespaces in scope */ + + /* error reporting mechanism */ + void *userData; /* user specific data block */ + xmlStructuredErrorFunc error; /* the callback in case of errors */ + xmlError lastError; /* the last error */ + xmlNodePtr debugNode; /* the source node XSLT */ + + /* dictionary */ + xmlDictPtr dict; /* dictionary if any */ + + int flags; /* flags to control compilation */ + + /* Cache for reusal of XPath objects */ + void *cache; +}; + +/* + * The structure of a compiled expression form is not public. + */ + +typedef struct _xmlXPathCompExpr xmlXPathCompExpr; +typedef xmlXPathCompExpr *xmlXPathCompExprPtr; + +/** + * xmlXPathParserContext: + * + * An XPath parser context. It contains pure parsing informations, + * an xmlXPathContext, and the stack of objects. + */ +struct _xmlXPathParserContext { + const xmlChar *cur; /* the current char being parsed */ + const xmlChar *base; /* the full expression */ + + int error; /* error code */ + + xmlXPathContextPtr context; /* the evaluation context */ + xmlXPathObjectPtr value; /* the current value */ + int valueNr; /* number of values stacked */ + int valueMax; /* max number of values stacked */ + xmlXPathObjectPtr *valueTab; /* stack of values */ + + xmlXPathCompExprPtr comp; /* the precompiled expression */ + int xptr; /* it this an XPointer expression */ + xmlNodePtr ancestor; /* used for walking preceding axis */ + + int valueFrame; /* used to limit Pop on the stack */ +}; + +/************************************************************************ + * * + * Public API * + * * + ************************************************************************/ + +/** + * Objects and Nodesets handling + */ + +XMLPUBVAR double xmlXPathNAN; +XMLPUBVAR double xmlXPathPINF; +XMLPUBVAR double xmlXPathNINF; + +/* These macros may later turn into functions */ +/** + * xmlXPathNodeSetGetLength: + * @ns: a node-set + * + * Implement a functionality similar to the DOM NodeList.length. + * + * Returns the number of nodes in the node-set. + */ +#define xmlXPathNodeSetGetLength(ns) ((ns) ? (ns)->nodeNr : 0) +/** + * xmlXPathNodeSetItem: + * @ns: a node-set + * @index: index of a node in the set + * + * Implements a functionality similar to the DOM NodeList.item(). + * + * Returns the xmlNodePtr at the given @index in @ns or NULL if + * @index is out of range (0 to length-1) + */ +#define xmlXPathNodeSetItem(ns, index) \ + ((((ns) != NULL) && \ + ((index) >= 0) && ((index) < (ns)->nodeNr)) ? \ + (ns)->nodeTab[(index)] \ + : NULL) +/** + * xmlXPathNodeSetIsEmpty: + * @ns: a node-set + * + * Checks whether @ns is empty or not. + * + * Returns %TRUE if @ns is an empty node-set. + */ +#define xmlXPathNodeSetIsEmpty(ns) \ + (((ns) == NULL) || ((ns)->nodeNr == 0) || ((ns)->nodeTab == NULL)) + + +XMLPUBFUN void XMLCALL + xmlXPathFreeObject (xmlXPathObjectPtr obj); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeSetCreate (xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathFreeNodeSetList (xmlXPathObjectPtr obj); +XMLPUBFUN void XMLCALL + xmlXPathFreeNodeSet (xmlNodeSetPtr obj); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathObjectCopy (xmlXPathObjectPtr val); +XMLPUBFUN int XMLCALL + xmlXPathCmpNodes (xmlNodePtr node1, + xmlNodePtr node2); +/** + * Conversion functions to basic types. + */ +XMLPUBFUN int XMLCALL + xmlXPathCastNumberToBoolean (double val); +XMLPUBFUN int XMLCALL + xmlXPathCastStringToBoolean (const xmlChar * val); +XMLPUBFUN int XMLCALL + xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns); +XMLPUBFUN int XMLCALL + xmlXPathCastToBoolean (xmlXPathObjectPtr val); + +XMLPUBFUN double XMLCALL + xmlXPathCastBooleanToNumber (int val); +XMLPUBFUN double XMLCALL + xmlXPathCastStringToNumber (const xmlChar * val); +XMLPUBFUN double XMLCALL + xmlXPathCastNodeToNumber (xmlNodePtr node); +XMLPUBFUN double XMLCALL + xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns); +XMLPUBFUN double XMLCALL + xmlXPathCastToNumber (xmlXPathObjectPtr val); + +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastBooleanToString (int val); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastNumberToString (double val); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastNodeToString (xmlNodePtr node); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastNodeSetToString (xmlNodeSetPtr ns); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastToString (xmlXPathObjectPtr val); + +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathConvertBoolean (xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathConvertNumber (xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathConvertString (xmlXPathObjectPtr val); + +/** + * Context handling. + */ +XMLPUBFUN xmlXPathContextPtr XMLCALL + xmlXPathNewContext (xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlXPathFreeContext (xmlXPathContextPtr ctxt); +XMLPUBFUN int XMLCALL + xmlXPathContextSetCache(xmlXPathContextPtr ctxt, + int active, + int value, + int options); +/** + * Evaluation functions. + */ +XMLPUBFUN long XMLCALL + xmlXPathOrderDocElems (xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlXPathSetContextNode (xmlNodePtr node, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNodeEval (xmlNodePtr node, + const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathEval (const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathEvalExpression (const xmlChar *str, + xmlXPathContextPtr ctxt); +XMLPUBFUN int XMLCALL + xmlXPathEvalPredicate (xmlXPathContextPtr ctxt, + xmlXPathObjectPtr res); +/** + * Separate compilation/evaluation entry points. + */ +XMLPUBFUN xmlXPathCompExprPtr XMLCALL + xmlXPathCompile (const xmlChar *str); +XMLPUBFUN xmlXPathCompExprPtr XMLCALL + xmlXPathCtxtCompile (xmlXPathContextPtr ctxt, + const xmlChar *str); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathCompiledEval (xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctx); +XMLPUBFUN int XMLCALL + xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctxt); +XMLPUBFUN void XMLCALL + xmlXPathFreeCompExpr (xmlXPathCompExprPtr comp); +#endif /* LIBXML_XPATH_ENABLED */ +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN void XMLCALL + xmlXPathInit (void); +XMLPUBFUN int XMLCALL + xmlXPathIsNaN (double val); +XMLPUBFUN int XMLCALL + xmlXPathIsInf (double val); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED*/ +#endif /* ! __XML_XPATH_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpathInternals.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpathInternals.h new file mode 100644 index 0000000..76a6b48 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpathInternals.h @@ -0,0 +1,632 @@ +/* + * Summary: internal interfaces for XML Path Language implementation + * Description: internal interfaces for XML Path Language implementation + * used to build new modules on top of XPath like XPointer and + * XSLT + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPATH_INTERNALS_H__ +#define __XML_XPATH_INTERNALS_H__ + +#include +#include + +#ifdef LIBXML_XPATH_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************ + * * + * Helpers * + * * + ************************************************************************/ + +/* + * Many of these macros may later turn into functions. They + * shouldn't be used in #ifdef's preprocessor instructions. + */ +/** + * xmlXPathSetError: + * @ctxt: an XPath parser context + * @err: an xmlXPathError code + * + * Raises an error. + */ +#define xmlXPathSetError(ctxt, err) \ + { xmlXPatherror((ctxt), __FILE__, __LINE__, (err)); \ + if ((ctxt) != NULL) (ctxt)->error = (err); } + +/** + * xmlXPathSetArityError: + * @ctxt: an XPath parser context + * + * Raises an XPATH_INVALID_ARITY error. + */ +#define xmlXPathSetArityError(ctxt) \ + xmlXPathSetError((ctxt), XPATH_INVALID_ARITY) + +/** + * xmlXPathSetTypeError: + * @ctxt: an XPath parser context + * + * Raises an XPATH_INVALID_TYPE error. + */ +#define xmlXPathSetTypeError(ctxt) \ + xmlXPathSetError((ctxt), XPATH_INVALID_TYPE) + +/** + * xmlXPathGetError: + * @ctxt: an XPath parser context + * + * Get the error code of an XPath context. + * + * Returns the context error. + */ +#define xmlXPathGetError(ctxt) ((ctxt)->error) + +/** + * xmlXPathCheckError: + * @ctxt: an XPath parser context + * + * Check if an XPath error was raised. + * + * Returns true if an error has been raised, false otherwise. + */ +#define xmlXPathCheckError(ctxt) ((ctxt)->error != XPATH_EXPRESSION_OK) + +/** + * xmlXPathGetDocument: + * @ctxt: an XPath parser context + * + * Get the document of an XPath context. + * + * Returns the context document. + */ +#define xmlXPathGetDocument(ctxt) ((ctxt)->context->doc) + +/** + * xmlXPathGetContextNode: + * @ctxt: an XPath parser context + * + * Get the context node of an XPath context. + * + * Returns the context node. + */ +#define xmlXPathGetContextNode(ctxt) ((ctxt)->context->node) + +XMLPUBFUN int XMLCALL + xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt); +XMLPUBFUN double XMLCALL + xmlXPathPopNumber (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathPopString (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt); +XMLPUBFUN void * XMLCALL + xmlXPathPopExternal (xmlXPathParserContextPtr ctxt); + +/** + * xmlXPathReturnBoolean: + * @ctxt: an XPath parser context + * @val: a boolean + * + * Pushes the boolean @val on the context stack. + */ +#define xmlXPathReturnBoolean(ctxt, val) \ + valuePush((ctxt), xmlXPathNewBoolean(val)) + +/** + * xmlXPathReturnTrue: + * @ctxt: an XPath parser context + * + * Pushes true on the context stack. + */ +#define xmlXPathReturnTrue(ctxt) xmlXPathReturnBoolean((ctxt), 1) + +/** + * xmlXPathReturnFalse: + * @ctxt: an XPath parser context + * + * Pushes false on the context stack. + */ +#define xmlXPathReturnFalse(ctxt) xmlXPathReturnBoolean((ctxt), 0) + +/** + * xmlXPathReturnNumber: + * @ctxt: an XPath parser context + * @val: a double + * + * Pushes the double @val on the context stack. + */ +#define xmlXPathReturnNumber(ctxt, val) \ + valuePush((ctxt), xmlXPathNewFloat(val)) + +/** + * xmlXPathReturnString: + * @ctxt: an XPath parser context + * @str: a string + * + * Pushes the string @str on the context stack. + */ +#define xmlXPathReturnString(ctxt, str) \ + valuePush((ctxt), xmlXPathWrapString(str)) + +/** + * xmlXPathReturnEmptyString: + * @ctxt: an XPath parser context + * + * Pushes an empty string on the stack. + */ +#define xmlXPathReturnEmptyString(ctxt) \ + valuePush((ctxt), xmlXPathNewCString("")) + +/** + * xmlXPathReturnNodeSet: + * @ctxt: an XPath parser context + * @ns: a node-set + * + * Pushes the node-set @ns on the context stack. + */ +#define xmlXPathReturnNodeSet(ctxt, ns) \ + valuePush((ctxt), xmlXPathWrapNodeSet(ns)) + +/** + * xmlXPathReturnEmptyNodeSet: + * @ctxt: an XPath parser context + * + * Pushes an empty node-set on the context stack. + */ +#define xmlXPathReturnEmptyNodeSet(ctxt) \ + valuePush((ctxt), xmlXPathNewNodeSet(NULL)) + +/** + * xmlXPathReturnExternal: + * @ctxt: an XPath parser context + * @val: user data + * + * Pushes user data on the context stack. + */ +#define xmlXPathReturnExternal(ctxt, val) \ + valuePush((ctxt), xmlXPathWrapExternal(val)) + +/** + * xmlXPathStackIsNodeSet: + * @ctxt: an XPath parser context + * + * Check if the current value on the XPath stack is a node set or + * an XSLT value tree. + * + * Returns true if the current object on the stack is a node-set. + */ +#define xmlXPathStackIsNodeSet(ctxt) \ + (((ctxt)->value != NULL) \ + && (((ctxt)->value->type == XPATH_NODESET) \ + || ((ctxt)->value->type == XPATH_XSLT_TREE))) + +/** + * xmlXPathStackIsExternal: + * @ctxt: an XPath parser context + * + * Checks if the current value on the XPath stack is an external + * object. + * + * Returns true if the current object on the stack is an external + * object. + */ +#define xmlXPathStackIsExternal(ctxt) \ + ((ctxt->value != NULL) && (ctxt->value->type == XPATH_USERS)) + +/** + * xmlXPathEmptyNodeSet: + * @ns: a node-set + * + * Empties a node-set. + */ +#define xmlXPathEmptyNodeSet(ns) \ + { while ((ns)->nodeNr > 0) (ns)->nodeTab[--(ns)->nodeNr] = NULL; } + +/** + * CHECK_ERROR: + * + * Macro to return from the function if an XPath error was detected. + */ +#define CHECK_ERROR \ + if (ctxt->error != XPATH_EXPRESSION_OK) return + +/** + * CHECK_ERROR0: + * + * Macro to return 0 from the function if an XPath error was detected. + */ +#define CHECK_ERROR0 \ + if (ctxt->error != XPATH_EXPRESSION_OK) return(0) + +/** + * XP_ERROR: + * @X: the error code + * + * Macro to raise an XPath error and return. + */ +#define XP_ERROR(X) \ + { xmlXPathErr(ctxt, X); return; } + +/** + * XP_ERROR0: + * @X: the error code + * + * Macro to raise an XPath error and return 0. + */ +#define XP_ERROR0(X) \ + { xmlXPathErr(ctxt, X); return(0); } + +/** + * CHECK_TYPE: + * @typeval: the XPath type + * + * Macro to check that the value on top of the XPath stack is of a given + * type. + */ +#define CHECK_TYPE(typeval) \ + if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + XP_ERROR(XPATH_INVALID_TYPE) + +/** + * CHECK_TYPE0: + * @typeval: the XPath type + * + * Macro to check that the value on top of the XPath stack is of a given + * type. Return(0) in case of failure + */ +#define CHECK_TYPE0(typeval) \ + if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + XP_ERROR0(XPATH_INVALID_TYPE) + +/** + * CHECK_ARITY: + * @x: the number of expected args + * + * Macro to check that the number of args passed to an XPath function matches. + */ +#define CHECK_ARITY(x) \ + if (ctxt == NULL) return; \ + if (nargs != (x)) \ + XP_ERROR(XPATH_INVALID_ARITY); \ + if (ctxt->valueNr < ctxt->valueFrame + (x)) \ + XP_ERROR(XPATH_STACK_ERROR); + +/** + * CAST_TO_STRING: + * + * Macro to try to cast the value on the top of the XPath stack to a string. + */ +#define CAST_TO_STRING \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \ + xmlXPathStringFunction(ctxt, 1); + +/** + * CAST_TO_NUMBER: + * + * Macro to try to cast the value on the top of the XPath stack to a number. + */ +#define CAST_TO_NUMBER \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \ + xmlXPathNumberFunction(ctxt, 1); + +/** + * CAST_TO_BOOLEAN: + * + * Macro to try to cast the value on the top of the XPath stack to a boolean. + */ +#define CAST_TO_BOOLEAN \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \ + xmlXPathBooleanFunction(ctxt, 1); + +/* + * Variable Lookup forwarding. + */ + +XMLPUBFUN void XMLCALL + xmlXPathRegisterVariableLookup (xmlXPathContextPtr ctxt, + xmlXPathVariableLookupFunc f, + void *data); + +/* + * Function Lookup forwarding. + */ + +XMLPUBFUN void XMLCALL + xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, + xmlXPathFuncLookupFunc f, + void *funcCtxt); + +/* + * Error reporting. + */ +XMLPUBFUN void XMLCALL + xmlXPatherror (xmlXPathParserContextPtr ctxt, + const char *file, + int line, + int no); + +XMLPUBFUN void XMLCALL + xmlXPathErr (xmlXPathParserContextPtr ctxt, + int error); + +#ifdef LIBXML_DEBUG_ENABLED +XMLPUBFUN void XMLCALL + xmlXPathDebugDumpObject (FILE *output, + xmlXPathObjectPtr cur, + int depth); +XMLPUBFUN void XMLCALL + xmlXPathDebugDumpCompExpr(FILE *output, + xmlXPathCompExprPtr comp, + int depth); +#endif +/** + * NodeSet handling. + */ +XMLPUBFUN int XMLCALL + xmlXPathNodeSetContains (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathDifference (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathIntersection (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathDistinctSorted (xmlNodeSetPtr nodes); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathDistinct (xmlNodeSetPtr nodes); + +XMLPUBFUN int XMLCALL + xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeLeading (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathLeading (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeTrailing (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathTrailing (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + + +/** + * Extending a context. + */ + +XMLPUBFUN int XMLCALL + xmlXPathRegisterNs (xmlXPathContextPtr ctxt, + const xmlChar *prefix, + const xmlChar *ns_uri); +XMLPUBFUN const xmlChar * XMLCALL + xmlXPathNsLookup (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + xmlXPathRegisteredNsCleanup (xmlXPathContextPtr ctxt); + +XMLPUBFUN int XMLCALL + xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, + const xmlChar *name, + xmlXPathFunction f); +XMLPUBFUN int XMLCALL + xmlXPathRegisterFuncNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathFunction f); +XMLPUBFUN int XMLCALL + xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, + const xmlChar *name, + xmlXPathObjectPtr value); +XMLPUBFUN int XMLCALL + xmlXPathRegisterVariableNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathObjectPtr value); +XMLPUBFUN xmlXPathFunction XMLCALL + xmlXPathFunctionLookup (xmlXPathContextPtr ctxt, + const xmlChar *name); +XMLPUBFUN xmlXPathFunction XMLCALL + xmlXPathFunctionLookupNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XMLPUBFUN void XMLCALL + xmlXPathRegisteredFuncsCleanup (xmlXPathContextPtr ctxt); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathVariableLookup (xmlXPathContextPtr ctxt, + const xmlChar *name); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathVariableLookupNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XMLPUBFUN void XMLCALL + xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt); + +/** + * Utilities to extend XPath. + */ +XMLPUBFUN xmlXPathParserContextPtr XMLCALL + xmlXPathNewParserContext (const xmlChar *str, + xmlXPathContextPtr ctxt); +XMLPUBFUN void XMLCALL + xmlXPathFreeParserContext (xmlXPathParserContextPtr ctxt); + +/* TODO: remap to xmlXPathValuePop and Push. */ +XMLPUBFUN xmlXPathObjectPtr XMLCALL + valuePop (xmlXPathParserContextPtr ctxt); +XMLPUBFUN int XMLCALL + valuePush (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr value); + +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewString (const xmlChar *val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewCString (const char *val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapString (xmlChar *val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapCString (char * val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewFloat (double val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewBoolean (int val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewNodeSet (xmlNodePtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewValueTree (xmlNodePtr val); +XMLPUBFUN int XMLCALL + xmlXPathNodeSetAdd (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN int XMLCALL + xmlXPathNodeSetAddUnique (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN int XMLCALL + xmlXPathNodeSetAddNs (xmlNodeSetPtr cur, + xmlNodePtr node, + xmlNsPtr ns); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetSort (xmlNodeSetPtr set); + +XMLPUBFUN void XMLCALL + xmlXPathRoot (xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL + xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathParseName (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathParseNCName (xmlXPathParserContextPtr ctxt); + +/* + * Existing functions. + */ +XMLPUBFUN double XMLCALL + xmlXPathStringEvalNumber (const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlXPathEvaluatePredicateResult (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr res); +XMLPUBFUN void XMLCALL + xmlXPathRegisterAllFunctions (xmlXPathContextPtr ctxt); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeSetMerge (xmlNodeSetPtr val1, + xmlNodeSetPtr val2); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetDel (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetRemove (xmlNodeSetPtr cur, + int val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewNodeSetList (xmlNodeSetPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapNodeSet (xmlNodeSetPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapExternal (void *val); + +XMLPUBFUN int XMLCALL xmlXPathEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int XMLCALL xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int XMLCALL xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict); +XMLPUBFUN void XMLCALL xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathAddValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathSubValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathMultValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathDivValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathModValues(xmlXPathParserContextPtr ctxt); + +XMLPUBFUN int XMLCALL xmlXPathIsNodeType(const xmlChar *name); + +/* + * Some of the axis navigation routines. + */ +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextChild(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextParent(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +/* + * The official core of XPath functions. + */ +XMLPUBFUN void XMLCALL xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs); + +/** + * Really internal functions + */ +XMLPUBFUN void XMLCALL xmlXPathNodeSetFreeNs(xmlNsPtr ns); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPATH_ENABLED */ +#endif /* ! __XML_XPATH_INTERNALS_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpointer.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpointer.h new file mode 100644 index 0000000..b99112b --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/libxml/xpointer.h @@ -0,0 +1,114 @@ +/* + * Summary: API to handle XML Pointers + * Description: API to handle XML Pointers + * Base implementation was made accordingly to + * W3C Candidate Recommendation 7 June 2000 + * http://www.w3.org/TR/2000/CR-xptr-20000607 + * + * Added support for the element() scheme described in: + * W3C Proposed Recommendation 13 November 2002 + * http://www.w3.org/TR/2002/PR-xptr-element-20021113/ + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPTR_H__ +#define __XML_XPTR_H__ + +#include + +#ifdef LIBXML_XPTR_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A Location Set + */ +typedef struct _xmlLocationSet xmlLocationSet; +typedef xmlLocationSet *xmlLocationSetPtr; +struct _xmlLocationSet { + int locNr; /* number of locations in the set */ + int locMax; /* size of the array as allocated */ + xmlXPathObjectPtr *locTab;/* array of locations */ +}; + +/* + * Handling of location sets. + */ + +XMLPUBFUN xmlLocationSetPtr XMLCALL + xmlXPtrLocationSetCreate (xmlXPathObjectPtr val); +XMLPUBFUN void XMLCALL + xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); +XMLPUBFUN xmlLocationSetPtr XMLCALL + xmlXPtrLocationSetMerge (xmlLocationSetPtr val1, + xmlLocationSetPtr val2); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRange (xmlNodePtr start, + int startindex, + xmlNodePtr end, + int endindex); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangePoints (xmlXPathObjectPtr start, + xmlXPathObjectPtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangeNodePoint (xmlNodePtr start, + xmlXPathObjectPtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangePointNode (xmlXPathObjectPtr start, + xmlNodePtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangeNodes (xmlNodePtr start, + xmlNodePtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewLocationSetNodes (xmlNodePtr start, + xmlNodePtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangeNodeObject (xmlNodePtr start, + xmlXPathObjectPtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewCollapsedRange (xmlNodePtr start); +XMLPUBFUN void XMLCALL + xmlXPtrLocationSetAdd (xmlLocationSetPtr cur, + xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrWrapLocationSet (xmlLocationSetPtr val); +XMLPUBFUN void XMLCALL + xmlXPtrLocationSetDel (xmlLocationSetPtr cur, + xmlXPathObjectPtr val); +XMLPUBFUN void XMLCALL + xmlXPtrLocationSetRemove (xmlLocationSetPtr cur, + int val); + +/* + * Functions. + */ +XMLPUBFUN xmlXPathContextPtr XMLCALL + xmlXPtrNewContext (xmlDocPtr doc, + xmlNodePtr here, + xmlNodePtr origin); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrEval (const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN void XMLCALL + xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XMLPUBFUN xmlNodePtr XMLCALL + xmlXPtrBuildNodeList (xmlXPathObjectPtr obj); +XMLPUBFUN void XMLCALL + xmlXPtrEvalRangePredicate (xmlXPathParserContextPtr ctxt); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPTR_ENABLED */ +#endif /* __XML_XPTR_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/win32config.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/win32config.h new file mode 100644 index 0000000..40cf7df --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/win32config.h @@ -0,0 +1,128 @@ +#ifndef __LIBXML_WIN32_CONFIG__ +#define __LIBXML_WIN32_CONFIG__ + +#define HAVE_CTYPE_H +#define HAVE_STDARG_H +#define HAVE_MALLOC_H +#define HAVE_ERRNO_H +#define SEND_ARG2_CAST +#define GETHOSTBYNAME_ARG_CAST + +#if defined(_WIN32_WCE) +#undef HAVE_ERRNO_H +#include +#include "wincecompat.h" +#else +#define HAVE_SYS_STAT_H +#define HAVE__STAT +#define HAVE_STAT +#define HAVE_STDLIB_H +#define HAVE_TIME_H +#define HAVE_FCNTL_H +#include +#include +#endif + +#include + +#ifndef ICONV_CONST +#define ICONV_CONST const +#endif + +#ifdef NEED_SOCKETS +#include +#endif + +/* + * Windows platforms may define except + */ +#undef except + +#define HAVE_ISINF +#define HAVE_ISNAN +#include +#if defined(_MSC_VER) || defined(__BORLANDC__) +/* MS C-runtime has functions which can be used in order to determine if + a given floating-point variable contains NaN, (+-)INF. These are + preferred, because floating-point technology is considered propriatary + by MS and we can assume that their functions know more about their + oddities than we do. */ +#include +/* Bjorn Reese figured a quite nice construct for isinf() using the _fpclass + function. */ +#ifndef isinf +#define isinf(d) ((_fpclass(d) == _FPCLASS_PINF) ? 1 \ + : ((_fpclass(d) == _FPCLASS_NINF) ? -1 : 0)) +#endif +/* _isnan(x) returns nonzero if (x == NaN) and zero otherwise. */ +#ifndef isnan +#define isnan(d) (_isnan(d)) +#endif +#else /* _MSC_VER */ +#ifndef isinf +static int isinf (double d) { + int expon = 0; + double val = frexp (d, &expon); + if (expon == 1025) { + if (val == 0.5) { + return 1; + } else if (val == -0.5) { + return -1; + } else { + return 0; + } + } else { + return 0; + } +} +#endif +#ifndef isnan +static int isnan (double d) { + int expon = 0; + double val = frexp (d, &expon); + if (expon == 1025) { + if (val == 0.5) { + return 0; + } else if (val == -0.5) { + return 0; + } else { + return 1; + } + } else { + return 0; + } +} +#endif +#endif /* _MSC_VER */ + +#if defined(_MSC_VER) +#define mkdir(p,m) _mkdir(p) +#if _MSC_VER < 1900 +#define snprintf _snprintf +#endif +#if _MSC_VER < 1500 +#define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a) +#endif +#elif defined(__MINGW32__) +#define mkdir(p,m) _mkdir(p) +#endif + +/* Threading API to use should be specified here for compatibility reasons. + This is however best specified on the compiler's command-line. */ +#if defined(LIBXML_THREAD_ENABLED) +#if !defined(HAVE_PTHREAD_H) && !defined(HAVE_WIN32_THREADS) && !defined(_WIN32_WCE) +#define HAVE_WIN32_THREADS +#endif +#endif + +/* Some third-party libraries far from our control assume the following + is defined, which it is not if we don't include windows.h. */ +#if !defined(FALSE) +#define FALSE 0 +#endif +#if !defined(TRUE) +#define TRUE (!(FALSE)) +#endif + +#endif /* __LIBXML_WIN32_CONFIG__ */ + diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/wsockcompat.h b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/wsockcompat.h new file mode 100644 index 0000000..e6a1a99 --- /dev/null +++ b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/include/wsockcompat.h @@ -0,0 +1,86 @@ +/* include/wsockcompat.h + * Windows -> Berkeley Sockets compatibility things. + */ + +#if !defined __XML_WSOCKCOMPAT_H__ +#define __XML_WSOCKCOMPAT_H__ + +#ifdef _WIN32_WCE +#include +#else +#undef HAVE_ERRNO_H +#include + +/* the following is a workaround a problem for 'inline' keyword in said + header when compiled with Borland C++ 6 */ +#if defined(__BORLANDC__) && !defined(__cplusplus) +#define inline __inline +#define _inline __inline +#endif + +#include + +/* Check if ws2tcpip.h is a recent version which provides getaddrinfo() */ +#if defined(GetAddrInfo) +#include +#define HAVE_GETADDRINFO +#endif +#endif + +#if defined( __MINGW32__ ) || defined( _MSC_VER ) +/* Include here to ensure that it doesn't get included later + * (e.g. by iconv.h) and overwrites the definition of EWOULDBLOCK. */ +#include +#undef EWOULDBLOCK +#endif + +#if !defined SOCKLEN_T +#define SOCKLEN_T int +#endif + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ESHUTDOWN WSAESHUTDOWN + +#if (!defined(_MSC_VER) || (_MSC_VER < 1600)) +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +/* These cause conflicts with the codes from errno.h. Since they are + not used in the relevant code (nanoftp, nanohttp), we can leave + them disabled. +#define ENAMETOOLONG WSAENAMETOOLONG +#define ENOTEMPTY WSAENOTEMPTY +*/ +#endif /* _MSC_VER */ + +#endif /* __XML_WSOCKCOMPAT_H__ */ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Debug/libxml2.lib b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Debug/libxml2.lib new file mode 100644 index 0000000..79f1562 Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Debug/libxml2.lib differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Debug/libxml2.pdb b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Debug/libxml2.pdb new file mode 100644 index 0000000..ea68811 Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Debug/libxml2.pdb differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Release/libxml2.lib b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Release/libxml2.lib new file mode 100644 index 0000000..658c4ee Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x64/static/Release/libxml2.lib differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Debug/libxml2.lib b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Debug/libxml2.lib new file mode 100644 index 0000000..cffeb6d Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Debug/libxml2.lib differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Debug/libxml2.pdb b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Debug/libxml2.pdb new file mode 100644 index 0000000..dd1b226 Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Debug/libxml2.pdb differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Release/libxml2.lib b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Release/libxml2.lib new file mode 100644 index 0000000..17145e5 Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/lib/native/libs/x86/static/Release/libxml2.lib differ diff --git a/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/libxml2-vc140-static-32_64.2.9.4.1.nupkg b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/libxml2-vc140-static-32_64.2.9.4.1.nupkg new file mode 100644 index 0000000..9d57539 Binary files /dev/null and b/Charcoal/Charcoal/packages/libxml2-vc140-static-32_64.2.9.4.1/libxml2-vc140-static-32_64.2.9.4.1.nupkg differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/.signature.p7s b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/.signature.p7s new file mode 100644 index 0000000..5a964d5 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/.signature.p7s differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/build/native/zlib128-vc140-static-32_64.targets b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/build/native/zlib128-vc140-static-32_64.targets new file mode 100644 index 0000000..e3f8710 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/build/native/zlib128-vc140-static-32_64.targets @@ -0,0 +1,13 @@ + + + + + $(MSBuildThisFileDirectory)..\..\lib\native\include\;%(AdditionalIncludeDirectories) + + + $(MSBuildThisFileDirectory)..\..\lib\native\libs\x64\static\$(Configuration);%(AdditionalLibraryDirectories) + $(MSBuildThisFileDirectory)..\..\lib\native\libs\x86\static\$(Configuration);%(AdditionalLibraryDirectories) + zlibstat.lib;%(AdditionalDependencies) + + + \ No newline at end of file diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/crypt.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/crypt.h new file mode 100644 index 0000000..1e9e820 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/crypt.h @@ -0,0 +1,131 @@ +/* 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. +*/ + +#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 z_crc_t* pcrc_32_tab) +{ + 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 z_crc_t* 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 z_crc_t* 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(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const z_crc_t* 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> 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++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/ioapi.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/ioapi.h new file mode 100644 index 0000000..8dcbdb0 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/ioapi.h @@ -0,0 +1,208 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/iowin32.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/iowin32.h new file mode 100644 index 0000000..0ca0969 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/mztools.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/mztools.h new file mode 100644 index 0000000..a49a426 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/mztools.h @@ -0,0 +1,37 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/unzip.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/unzip.h new file mode 100644 index 0000000..2104e39 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +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_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zconf.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zconf.h new file mode 100644 index 0000000..9987a77 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zconf.h @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zip.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zip.h new file mode 100644 index 0000000..8aaebb6 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +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) + +#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((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + 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((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_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)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zlib.h b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zlib.h new file mode 100644 index 0000000..3e0c767 --- /dev/null +++ b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/include/zlib.h @@ -0,0 +1,1768 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + 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. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 8 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Debug/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Debug/zlibstat.lib new file mode 100644 index 0000000..2b7d9f1 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Debug/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Release/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Release/zlibstat.lib new file mode 100644 index 0000000..821b58e Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Release/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Release/zlibstat.pdb b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Release/zlibstat.pdb new file mode 100644 index 0000000..e8e71a6 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/Release/zlibstat.pdb differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/_Debug/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/_Debug/zlibstat.lib new file mode 100644 index 0000000..71fdd79 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/_Debug/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/_Release/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/_Release/zlibstat.lib new file mode 100644 index 0000000..321fd59 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x64/static/_Release/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Debug/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Debug/zlibstat.lib new file mode 100644 index 0000000..ea09742 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Debug/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Debug/zlibstat.pdb b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Debug/zlibstat.pdb new file mode 100644 index 0000000..69b3bdc Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Debug/zlibstat.pdb differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Release/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Release/zlibstat.lib new file mode 100644 index 0000000..d83cb60 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Release/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Release/zlibstat.pdb b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Release/zlibstat.pdb new file mode 100644 index 0000000..d1f30ea Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/Release/zlibstat.pdb differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/_Debug/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/_Debug/zlibstat.lib new file mode 100644 index 0000000..4c5f300 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/_Debug/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/_Release/zlibstat.lib b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/_Release/zlibstat.lib new file mode 100644 index 0000000..197e476 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/lib/native/libs/x86/static/_Release/zlibstat.lib differ diff --git a/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/zlib128-vc140-static-32_64.1.2.8.nupkg b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/zlib128-vc140-static-32_64.1.2.8.nupkg new file mode 100644 index 0000000..f14f813 Binary files /dev/null and b/Charcoal/Charcoal/packages/zlib128-vc140-static-32_64.1.2.8/zlib128-vc140-static-32_64.1.2.8.nupkg differ