/* * compression/DecompressorLHA.cpp * * Copyright 2009 Peter Barth * * This file is part of Milkytracker. * * Milkytracker 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. * * Milkytracker 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 Milkytracker. If not, see . * */ /* * DecompressorLHA.cpp * milkytracker_universal * * Created by Peter Barth on 22.06.08. * */ #include #include "DecompressorLHA.h" #include "XMFile.h" #include "XModule.h" #define LHA_BUFFER_SIZE 0x10000 namespace { static int lha_read_callback(void *handle, void *buf, size_t buf_len) { return static_cast(handle)->read(buf, 1, buf_len); } static const LHAInputStreamType lha_callbacks = { lha_read_callback, NULL, NULL }; // Simple wrapper for lha_reader_* class LHAReaderWrapper { public: explicit LHAReaderWrapper(XMFile& file) : input_stream(NULL), reader(NULL) { // Open input stream input_stream = lha_input_stream_new(&lha_callbacks, &file); if (input_stream == NULL) return; // Open reader reader = lha_reader_new(input_stream); } bool isOpen() const { return reader != NULL; } LHAFileHeader* nextFile() { return lha_reader_next_file(reader); } size_t read(void* buf, size_t length) { return lha_reader_read(reader, buf, length); } ~LHAReaderWrapper() { if (reader != NULL) lha_reader_free(reader); if (input_stream != NULL) lha_input_stream_free(input_stream); } private: LHAInputStream* input_stream; LHAReader* reader; LHAReaderWrapper(const LHAReaderWrapper&); LHAReaderWrapper& operator=(const LHAReaderWrapper&); }; } DecompressorLHA::DecompressorLHA(const PPSystemString& filename) : DecompressorBase(filename) { } bool DecompressorLHA::identify(XMFile& f) { f.seek(0); // Attempt to create the reader and read the header of the first file LHAReaderWrapper reader(f); if (!reader.isOpen()) return false; return reader.nextFile() != NULL; } const PPSimpleVector& DecompressorLHA::getDescriptors(Hints hint) const { descriptors.clear(); descriptors.add(new Descriptor("lha", "LHA Archive")); return descriptors; } bool DecompressorLHA::decompress(const PPSystemString& outFilename, Hints hint) { XMFile f(fileName); if (!f.isOpen()) return false; // Create reader object LHAReaderWrapper reader(f); if (!reader.isOpen()) return false; // Loop through each file until we find a sutible module while (1) { LHAFileHeader* header = reader.nextFile(); if (header == NULL) break; // Skip directories and symlinks if (strcmp(header->compress_method, LHA_COMPRESS_TYPE_DIR) == 0) continue; // Identify the current file mp_ubyte buf[LHA_BUFFER_SIZE]; memset(buf, 0, sizeof(buf)); size_t bytes_read = reader.read(buf, sizeof(buf)); if (bytes_read > 0 && XModule::identifyModule(buf) != NULL) { // Write to output file XMFile outFile(outFilename, true); if (!outFile.isOpenForWriting()) return false; // Decompress into outFile do { outFile.write(buf, 1, bytes_read); } while ((bytes_read = reader.read(buf, sizeof(buf))) > 0); return (bytes_read == 0); } } // No sutible modules found return false; } DecompressorBase* DecompressorLHA::clone() { return new DecompressorLHA(fileName); } static Decompressor::RegisterDecompressor registerDecompressor;