From da88bfde614318f59cde7b415ad6185bb0053666 Mon Sep 17 00:00:00 2001 From: NotKyon Date: Fri, 15 Jun 2018 10:03:50 -0700 Subject: [PATCH 1/3] Add BZip2 to the CMakeLists. --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1175f503..5bd106878 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,10 @@ find_package(ZLIB REQUIRED) include_directories(${ZLIB_INCLUDE_DIR}) link_directories(${ZLIB_LIBRARY_DIRS}) +find_package(BZip2 REQUIRED) +include_directories(${BZIP2_INCLUDE_DIR}) +link_directories(${BZIP2_LIBRARY_DIR}) + find_package(PNG REQUIRED) include_directories(${PNG_INCLUDE_DIR}) link_directories(${PNG_LIBRARY_DIRS}) @@ -183,13 +187,13 @@ endif() add_library(libau OBJECT ${au_sources} ${au_headers}) add_executable(arc_unpacker "${CMAKE_SOURCE_DIR}/src/main.cc" $) -target_link_libraries(arc_unpacker ${unicode} ${iconv} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${OPENSSL_LIBRARIES}) +target_link_libraries(arc_unpacker ${unicode} ${iconv} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${OPENSSL_LIBRARIES}) if(WEBP_FOUND) target_link_libraries(arc_unpacker ${WEBP_LIBRARIES}) endif() add_executable(run_tests ${test_sources} ${test_headers} "${CMAKE_SOURCE_DIR}/tests/main.cc" $) -target_link_libraries(run_tests ${iconv} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${OPENSSL_LIBRARIES}) +target_link_libraries(run_tests ${iconv} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${OPENSSL_LIBRARIES}) if(WEBP_FOUND) target_link_libraries(run_tests ${WEBP_LIBRARIES}) endif() From e87201abf8f24bce350444195cfcfeff51af33da Mon Sep 17 00:00:00 2001 From: NotKyon Date: Fri, 15 Jun 2018 10:04:46 -0700 Subject: [PATCH 2/3] Add BZip2 decoder, based on ZLib decoder. --- src/algo/pack/bzip2.cc | 151 +++++++++++++++++++++++++++++++++++++++++ src/algo/pack/bzip2.h | 39 +++++++++++ 2 files changed, 190 insertions(+) create mode 100644 src/algo/pack/bzip2.cc create mode 100644 src/algo/pack/bzip2.h diff --git a/src/algo/pack/bzip2.cc b/src/algo/pack/bzip2.cc new file mode 100644 index 000000000..63f06d495 --- /dev/null +++ b/src/algo/pack/bzip2.cc @@ -0,0 +1,151 @@ +// Copyright (C) 2018 by notkyon, 2016 rr- +// +// This file is part of arc_unpacker. +// +// arc_unpacker is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// arc_unpacker is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with arc_unpacker. If not, see . + +#include "algo/pack/bzip2.h" +#include +#include +#include +#include "algo/format.h" +#include "err.h" +#include "io/memory_byte_stream.h" + +using namespace au; +using namespace au::algo::pack; + +static const int buffer_size = 8192; + +constexpr uint64_t combine64( uint32_t lo32, uint32_t hi32 ) { + return uint64_t(hi32)<<32 | uint64_t(lo32); +} +inline uint64_t total_out( const bz_stream &s ) { + return combine64( s.total_out_lo32, s.total_out_hi32 ); +} +inline uint64_t total_in( const bz_stream &s ) { + return combine64( s.total_in_lo32, s.total_in_hi32 ); +} + +static bstr process_stream( + io::BaseByteStream &input_stream, + const std::function &init_func, + const std::function &process_func, + const std::function &end_func, + const std::string &error_message) +{ + bz_stream s; + std::memset(&s, 0, sizeof(s)); + if (init_func(s) != BZ_OK) + throw std::logic_error("Failed to initialize zlib stream"); + + bstr output, input_chunk, output_chunk(buffer_size); + size_t written = 0; + int ret; + const auto initial_pos = input_stream.pos(); + do + { + if (s.avail_in == 0) + { + input_chunk = input_stream.read( + std::min(input_stream.left(), buffer_size)); + s.next_in = const_cast(input_chunk.get()); + s.avail_in = input_chunk.size(); + } + + s.next_out = output_chunk.get(); + s.avail_out = output_chunk.size(); + + ret = process_func(s); + output += output_chunk.substr(0, total_out(s) - written); + written = total_out(s); + if (ret == BZ_PARAM_ERROR) // zlib equivalent: Z_BUF_ERROR + { + input_chunk += input_stream.read( + std::min(input_stream.left(), buffer_size)); + s.next_in = const_cast(input_chunk.get()); + s.avail_in = input_chunk.size(); + } + } + while (ret == BZ_OK); + + input_stream.seek(initial_pos + total_in(s)); + const auto pos = s.next_in - input_chunk.get(); + end_func(s); + if (ret != BZ_STREAM_END) + { + throw err::CorruptDataError(algo::format( + "%s (%s near %x)", + error_message.c_str(), + "unknown error", + pos)); + } + return output; +} + +bstr algo::pack::bz2_inflate( + io::BaseByteStream &input_stream) +{ + return process_stream( + input_stream, + [](bz_stream &s) + { + return BZ2_bzDecompressInit(&s, /*verbosity=*/0, /*small=*/0); + }, + [](bz_stream &s) + { + return BZ2_bzDecompress(&s); + }, + [](bz_stream &s) + { + return BZ2_bzDecompressEnd(&s); + }, + "Failed to inflate bzip2 stream"); +} + +bstr algo::pack::bz2_inflate(const bstr &input) +{ + io::MemoryByteStream input_stream(input); + return ::bz2_inflate(input_stream); +} + +bstr algo::pack::bz2_deflate( + const bstr &input, + const CompressionLevel compression_level) +{ + io::MemoryByteStream input_stream(input); + return process_stream( + input_stream, + [compression_level](bz_stream &s) + { + /* http://bzip.org/1.0.5/bzip2-manual-1.0.5.html#bzcompress-init */ + + const std::array levels { 9, 6, 1, 0 }; + + return BZ2_bzCompressInit( + &s, + levels.at(static_cast(compression_level)), + /*verbosity=*/0, + /*workFactory=*/200); + }, + [&input_stream](bz_stream &s) + { + return BZ2_bzCompress(&s, input_stream.left() ? BZ_RUN : BZ_FINISH); + }, + [](bz_stream &s) + { + return BZ2_bzCompressEnd(&s); + }, + "Failed to deflate stream"); +} diff --git a/src/algo/pack/bzip2.h b/src/algo/pack/bzip2.h new file mode 100644 index 000000000..925f8a123 --- /dev/null +++ b/src/algo/pack/bzip2.h @@ -0,0 +1,39 @@ +// Copyright (C) 2018 by notkyon, 2016 rr- +// +// This file is part of arc_unpacker. +// +// arc_unpacker is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// arc_unpacker is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with arc_unpacker. If not, see . + +#pragma once + +#include "algo/pack/compression_level.h" +#include "io/base_byte_stream.h" +#include "types.h" + +namespace au { +namespace algo { +namespace pack { + + bstr bz2_inflate( + io::BaseByteStream &input_stream); + + bstr bz2_inflate( + const bstr &input); + + bstr bz2_deflate( + const bstr &input, + const CompressionLevel = CompressionLevel::Best); + + +} } } From 1fd210246e74a02be8799adb7e2cbd422845a0c2 Mon Sep 17 00:00:00 2001 From: NotKyon Date: Fri, 15 Jun 2018 10:10:49 -0700 Subject: [PATCH 3/3] Add support for Umineko steam releases (Nbz compression type). --- src/dec/nscripter/nsa_archive_decoder.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/dec/nscripter/nsa_archive_decoder.cc b/src/dec/nscripter/nsa_archive_decoder.cc index 4da5a9b23..73576a18b 100644 --- a/src/dec/nscripter/nsa_archive_decoder.cc +++ b/src/dec/nscripter/nsa_archive_decoder.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016 by rr- +// Copyright (C) 2016 by rr-, 2018 by notkyon // // This file is part of arc_unpacker. // @@ -17,6 +17,7 @@ #include "dec/nscripter/nsa_archive_decoder.h" #include "algo/pack/lzss.h" +#include "algo/pack/bzip2.h" #include "algo/range.h" #include "dec/nscripter/nsa_encrypted_stream.h" #include "dec/nscripter/spb_image_decoder.h" @@ -33,6 +34,7 @@ namespace None = 0, Spb = 1, Lzss = 2, + Nbz = 4 }; struct CustomArchiveEntry final : dec::CompressedArchiveEntry @@ -122,6 +124,13 @@ std::unique_ptr NsaArchiveDecoder::read_file_impl( logger, decoder.decode(logger, spb_file), entry->path); } + if (entry->compression_type == CompressionType::Nbz) + { + return std::make_unique( + entry->path, + algo::pack::bz2_inflate(data.substr(4))); + } + throw err::NotSupportedError("Unknown compression type"); }