3
* hpi file class implementation
4
* Copyright (C) 2005 Christopher Han <xiphux@gmail.com>
6
* This file is part of hpiutil2.
8
* hpiutil2 is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* hpiutil2 is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with hpiutil2; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30
* @param fname path to target hpi file as a c string
32
hpiutil::hpifile::hpifile(const char *fname)
34
file = new scrambledfile(fname);
40
* @param fname path to target hpi file as a c++ string
42
hpiutil::hpifile::hpifile(std::string const &fname)
44
file = new scrambledfile(fname);
45
validate(fname.c_str());
51
hpiutil::hpifile::~hpifile()
58
* Reads the file's headers and ensures it is a legitimate hpi file
59
* also sets decryption key if present
60
* @param n path to target hpi
62
void hpiutil::hpifile::validate(const char *n)
65
header_hapimagic = file->readint();
66
if (header_hapimagic != HAPI_MAGIC) {
67
std::cerr << "File " << n << ": Invalid HAPI signature: 0x" << std::hex << header_hapimagic << std::endl;
70
header_bankmagic = file->readint();
71
if (header_bankmagic != HAPI_VERSION_MAGIC) {
72
if (header_bankmagic == BANK_MAGIC)
73
std::cerr << "File " << n << ": Bank subtype signature looks like a saved game: 0x" << std::hex << header_bankmagic << std::endl;
74
else if (header_bankmagic == HAPI2_VERSION_MAGIC)
75
std::cerr << "File " << n << ": HAPIv2 files not supported yet" << std::endl;
77
std::cerr << "File " << n << ": Invalid bank subtype signature: 0x" << std::hex << header_bankmagic << std::endl;
80
header_offset = file->readint();
81
header_key = file->readint();
82
header_diroffset = file->readint();
83
file->setkey(header_key);
85
flatlist.push_back(dirinfo("","",header_diroffset)); // <- result of dirinfo gets added twice?
90
* creates an hpientry object representing a given directory
91
* @return hpientry object for the directory
92
* @param parentname name of this object's parent (if applicable)
93
* @param dirname name of this directory
94
* @param offset offset in hpi file
96
hpiutil::hpientry_ptr hpiutil::hpifile::dirinfo(std::string const &parentname, std::string const &dirname, const boost::uint32_t offset)
98
std::vector<hpientry_ptr> listing;
99
std::string newparent;
103
newparent = parentname+PATHSEPARATOR+dirname;
105
boost::uint32_t entries = file->readint();
106
file->readint(); // unknown dword
107
for (boost::uint32_t i = 0; i < entries; i++) {
108
boost::uint32_t nameoffset = file->readint();
109
boost::uint32_t infooffset = file->readint();
110
boost::uint8_t entrytype = file->read();
111
boost::uint32_t currentpos = file->file.tellg();
112
file->seek(nameoffset);
113
std::string itemname = file->readstring();
114
file->seek(infooffset);
117
listing.push_back( fileinfo(newparent,itemname,infooffset));
120
listing.push_back( dirinfo(newparent,itemname,infooffset));
123
throw std::runtime_error("Unknown entry type");
126
file->seek(currentpos);
128
flatlist.push_back( hpientry_ptr(new hpientry(*this,parentname,dirname,(boost::uint32_t)0,(boost::uint32_t)0)));
129
flatlist.back()->directory = true;
130
flatlist.back()->subdir = listing;
131
return flatlist.back();
136
* creates an hpientry object representing a given file
137
* @return hpientry object for the file
138
* @param parentname name of this object's parent (if applicable)
139
* @param name name of the file
140
* @param offset offset in hpi file
142
hpiutil::hpientry_ptr hpiutil::hpifile::fileinfo(std::string const &parentname, std::string const &name, const boost::uint32_t offset)
144
boost::uint32_t doff = file->readint();
145
boost::uint32_t dsize = file->readint();
146
flatlist.push_back(hpientry_ptr( new hpientry(*this,parentname,name,doff,dsize) ) );
147
return flatlist.back();
152
* load a file's data into a buffer.
153
* @return the number of bytes read
154
* @param he hpientry for the target file
155
* @param data buffer to read data into
157
boost::uint32_t hpiutil::hpifile::getdata(hpientry_ptr const &he, boost::uint8_t *data)
159
if (he->file != this) {
160
std::cerr << "HPIentry does not match this HPIfile" << std::endl;
164
std::cerr << "HPIentry is a directory, not a file" << std::endl;
167
boost::uint32_t chunknum = bitdiv(he->size,16) + (bitmod(he->size,16)?1:0);
168
boost::uint32_t *chunksizes = (boost::uint32_t*)calloc(chunknum,sizeof(boost::uint32_t));
169
file->seek(he->offset);
170
for (boost::uint32_t i = 0; i < chunknum; i++)
171
chunksizes[i] = file->readint();
172
boost::uint32_t chunkoffset = he->offset + (chunknum * 4);
174
for (boost::uint32_t i = 0; i < chunknum; i++) {
175
boost::uint32_t chunksize = chunksizes[i];
176
substream *ss = new substream(*file,chunkoffset,chunksize);
177
sqshstream *sqsh = new sqshstream(*ss);
179
j += sqsh->readall(&data[j]);
180
chunkoffset += chunksize;