hpifile.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 193 行
CPP
193 行
/*
* hpifile.cpp
* hpi file class implementation
* Copyright (C) 2005 Christopher Han <xiphux@gmail.com>
*
* This file is part of hpiutil2.
*
* hpiutil2 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 2 of the License, or
* (at your option) any later version.
*
* hpiutil2 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 hpiutil2; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdexcept>
#include <sstream>
#include <iostream>
#include "hpifile.h"
/**
* Constructor
* @param fname path to target hpi file as a c string
*/
hpiutil::hpifile::hpifile(const char *fname)
{
file = new scrambledfile(fname);
validate(fname);
}
/**
* Constructor
* @param fname path to target hpi file as a c++ string
*/
hpiutil::hpifile::hpifile(std::string const &fname)
{
file = new scrambledfile(fname);
validate(fname.c_str());
}
/**
* Destructor
*/
hpiutil::hpifile::~hpifile()
{
delete file;
}
/**
* validate()
* Reads the file's headers and ensures it is a legitimate hpi file
* also sets decryption key if present
* @param n path to target hpi
*/
void hpiutil::hpifile::validate(const char *n)
{
valid = false;
header_hapimagic = file->readint();
if (header_hapimagic != HAPI_MAGIC) {
std::cerr << "File " << n << ": Invalid HAPI signature: 0x" << std::hex << header_hapimagic << std::endl;
return;
}
header_bankmagic = file->readint();
if (header_bankmagic != HAPI_VERSION_MAGIC) {
if (header_bankmagic == BANK_MAGIC)
std::cerr << "File " << n << ": Bank subtype signature looks like a saved game: 0x" << std::hex << header_bankmagic << std::endl;
else if (header_bankmagic == HAPI2_VERSION_MAGIC)
std::cerr << "File " << n << ": HAPIv2 files not supported yet" << std::endl;
else
std::cerr << "File " << n << ": Invalid bank subtype signature: 0x" << std::hex << header_bankmagic << std::endl;
return;
}
header_offset = file->readint();
header_key = file->readint();
header_diroffset = file->readint();
file->setkey(header_key);
valid = true;
flatlist.push_back(dirinfo("","",header_diroffset)); // <- result of dirinfo gets added twice?
}
/**
* dirinfo()
* creates an hpientry object representing a given directory
* @return hpientry object for the directory
* @param parentname name of this object's parent (if applicable)
* @param dirname name of this directory
* @param offset offset in hpi file
*/
hpiutil::hpientry_ptr hpiutil::hpifile::dirinfo(std::string const &parentname, std::string const &dirname, const boost::uint32_t offset)
{
std::vector<hpientry_ptr> listing;
std::string newparent;
if (parentname=="")
newparent = dirname;
else
newparent = parentname+PATHSEPARATOR+dirname;
file->seek(offset);
boost::uint32_t entries = file->readint();
file->readint(); // unknown dword
for (int i = 0; i < entries; i++) {
boost::uint32_t nameoffset = file->readint();
boost::uint32_t infooffset = file->readint();
boost::uint8_t entrytype = file->read();
boost::uint32_t currentpos = file->file.tellg();
file->seek(nameoffset);
std::string itemname = file->readstring();
file->seek(infooffset);
switch (entrytype) {
case 0:
listing.push_back( fileinfo(newparent,itemname,infooffset));
break;
case 1:
listing.push_back( dirinfo(newparent,itemname,infooffset));
break;
default:
throw std::runtime_error("Unknown entry type");
break;
}
file->seek(currentpos);
}
flatlist.push_back( hpientry_ptr(new hpientry(*this,parentname,dirname,(boost::uint32_t)0,(boost::uint32_t)0)));
flatlist.back()->directory = true;
flatlist.back()->subdir = listing;
return flatlist.back();
}
/**
* fileinfo()
* creates an hpientry object representing a given file
* @return hpientry object for the file
* @param parentname name of this object's parent (if applicable)
* @param name name of the file
* @param offset offset in hpi file
*/
hpiutil::hpientry_ptr hpiutil::hpifile::fileinfo(std::string const &parentname, std::string const &name, const boost::uint32_t offset)
{
boost::uint32_t doff = file->readint();
boost::uint32_t dsize = file->readint();
flatlist.push_back(hpientry_ptr( new hpientry(*this,parentname,name,doff,dsize) ) );
return flatlist.back();
}
/**
* getdata()
* load a file's data into a buffer.
* @return the number of bytes read
* @param he hpientry for the target file
* @param data buffer to read data into
*/
boost::uint32_t hpiutil::hpifile::getdata(hpientry_ptr const &he, boost::uint8_t *data)
{
if (he->file != this) {
std::cerr << "HPIentry does not match this HPIfile" << std::endl;
return 0;
}
if (he->directory) {
std::cerr << "HPIentry is a directory, not a file" << std::endl;
return 0;
}
boost::uint32_t chunknum = bitdiv(he->size,16) + (bitmod(he->size,16)?1:0);
boost::uint32_t *chunksizes = (boost::uint32_t*)calloc(chunknum,sizeof(boost::uint32_t));
file->seek(he->offset);
for (int i = 0; i < chunknum; i++)
chunksizes[i] = file->readint();
boost::uint32_t chunkoffset = he->offset + (chunknum * 4);
int j = 0;
for (int i = 0; i < chunknum; i++) {
boost::uint32_t chunksize = chunksizes[i];
substream *ss = new substream(*file,chunkoffset,chunksize);
sqshstream *sqsh = new sqshstream(*ss);
if (sqsh->valid) {
j += sqsh->readall(&data[j]);
chunkoffset += chunksize;
delete sqsh;
delete ss;
} else {
delete sqsh;
delete ss;
free(chunksizes);
return 0;
}
}
free(chunksizes);
return j;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?