Source

pyGAP / game / engine / io / fs / pack.cpp

//#define DUMP_FILE

#include "io/fs/base.h"
#include "io/fs/pack.h"

#include "io/file/decoder.h"
#include "io/file/base.h"

#include "formats/pack.h"


namespace io { namespace fs {


Pack::Pack() :
    Base(),
    header_(NULL),
    mft_(NULL),
    pack_(NULL),
    decoder_(NULL)
{}


void Pack::init(::io::file::Base* pack) {
    using namespace ::io::file;
    using namespace ::formats::pack;

    pack_ = pack;
    decoder_ = new Decoder();

    uint8_t* buffer = new uint8_t [HEADER_SIZE];
    pack_->read(buffer, sizeof(uint8_t), HEADER_SIZE);
    header_ = Header::allocate(buffer);

    buffer = new uint8_t [header_->mft_size];
    pack_->read(buffer, sizeof(uint8_t), header_->mft_size);
    mft_ = MFT::allocate(buffer);

    for (unsigned int i = 0; i < mft_->files_size; ++i)
        files_[mft_->files[i].hash] = &mft_->files[i];
}


Pack::~Pack() {
    using namespace ::formats::pack;
    Header::deallocate(header_);
    MFT::deallocate(mft_);
    delete decoder_;
    delete pack_;
}


uint32_t Pack::hash(const std::string& str) const {
    const unsigned int fnv_prime = 0x1000193;
    unsigned int hash = 0x811C9DC5;
    for(std::size_t i = 0; i < str.size(); i++) {
        hash *= fnv_prime;
        hash ^= str[i];
    }
    return hash;
}


::io::file::Base* Pack::open(const char* filename, const char* mode) const {
    return NULL;
}


uint8_t* Pack::read(const char* filename, const char* mode) const {
    uint32_t h = hash(filename);
    return read(h, mode);
}


uint8_t* Pack::read(const uint32_t& h, const char* mode) const {
    map_files_t::const_iterator it = files_.find(h);
    if (it == files_.end())
        return NULL;

    uint8_t* buffer = NULL;
    ::formats::pack::File* file = it->second;
    uint64_t offset = file->offset;
    pack_->seek(offset * header_->padding);

    if (file->zip_size)
        buffer = decoder_->decode(pack_, file->zip_size, file->size);
    else {
        buffer = new uint8_t [file->size];
        pack_->read(buffer, sizeof(uint8_t), file->size);
    }

#ifdef DUMP_FILE
    if (buffer) {
        ::io::file::Base* f = new ::io::file::Stdio();
        f->open("screen.png", "w+b");
        f->write(buffer, sizeof(uint8_t), file->size);
        delete f;
    }
#endif

    return buffer;
}


} /* namespace fs */ } /* namespace io */