~ubuntu-branches/ubuntu/natty/spring/natty

« back to all changes in this revision

Viewing changes to rts/lib/hpiutil2/hpifile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Scott Ritchie
  • Date: 2010-09-23 18:56:03 UTC
  • mfrom: (3.1.9 experimental)
  • Revision ID: james.westby@ubuntu.com-20100923185603-st97s5chplo42y7w
Tags: 0.82.5.1+dfsg1-1ubuntu1
* Latest upstream version for online play
* debian/control: Replace (rather than conflict) spring-engine
  - spring-engine will be a dummy package (LP: #612905)
  - also set maintainer to MOTU

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * hpifile.cpp
3
 
 * hpi file class implementation
4
 
 * Copyright (C) 2005 Christopher Han <xiphux@gmail.com>
5
 
 *
6
 
 * This file is part of hpiutil2.
7
 
 *
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.
12
 
 *
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.
17
 
 *
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
21
 
 */
22
 
 
23
 
#include <stdexcept>
24
 
#include <sstream>
25
 
#include <iostream>
26
 
#include "hpifile.h"
27
 
 
28
 
/**
29
 
 * Constructor
30
 
 * @param fname path to target hpi file as a c string
31
 
 */
32
 
hpiutil::hpifile::hpifile(const char *fname)
33
 
{
34
 
        file = new scrambledfile(fname);
35
 
        validate(fname);
36
 
}
37
 
 
38
 
/**
39
 
 * Constructor
40
 
 * @param fname path to target hpi file as a c++ string
41
 
 */
42
 
hpiutil::hpifile::hpifile(std::string const &fname)
43
 
{
44
 
        file = new scrambledfile(fname);
45
 
        validate(fname.c_str());
46
 
}
47
 
 
48
 
/**
49
 
 * Destructor
50
 
 */
51
 
hpiutil::hpifile::~hpifile()
52
 
{
53
 
        delete file;
54
 
}
55
 
 
56
 
/**
57
 
 * validate()
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
61
 
 */
62
 
void hpiutil::hpifile::validate(const char *n)
63
 
{
64
 
        valid = false;
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;
68
 
                return;
69
 
        }
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;
76
 
                else
77
 
                        std::cerr << "File " << n << ": Invalid bank subtype signature: 0x" << std::hex << header_bankmagic << std::endl;
78
 
                return;
79
 
        }
80
 
        header_offset = file->readint();
81
 
        header_key = file->readint();
82
 
        header_diroffset = file->readint();
83
 
        file->setkey(header_key);
84
 
        valid = true;
85
 
        flatlist.push_back(dirinfo("","",header_diroffset)); // <- result of dirinfo gets added twice?
86
 
}
87
 
 
88
 
/**
89
 
 * dirinfo()
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
95
 
 */
96
 
hpiutil::hpientry_ptr hpiutil::hpifile::dirinfo(std::string const &parentname, std::string const &dirname, const boost::uint32_t offset)
97
 
{
98
 
        std::vector<hpientry_ptr> listing;
99
 
        std::string newparent;
100
 
        if (parentname=="")
101
 
                newparent = dirname;
102
 
        else
103
 
                newparent = parentname+PATHSEPARATOR+dirname;
104
 
        file->seek(offset);
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);
115
 
                switch (entrytype) {
116
 
                        case 0:
117
 
                                listing.push_back( fileinfo(newparent,itemname,infooffset));
118
 
                                break;
119
 
                        case 1:
120
 
                                listing.push_back( dirinfo(newparent,itemname,infooffset));
121
 
                                break;
122
 
                        default:
123
 
                                throw std::runtime_error("Unknown entry type");
124
 
                                break;
125
 
                }
126
 
                file->seek(currentpos);
127
 
        }
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();
132
 
}
133
 
 
134
 
/**
135
 
 * fileinfo()
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
141
 
 */
142
 
hpiutil::hpientry_ptr hpiutil::hpifile::fileinfo(std::string const &parentname, std::string const &name, const boost::uint32_t offset)
143
 
{
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();
148
 
}
149
 
 
150
 
/**
151
 
 * getdata()
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
156
 
 */
157
 
boost::uint32_t hpiutil::hpifile::getdata(hpientry_ptr const &he, boost::uint8_t *data)
158
 
{
159
 
        if (he->file != this) {
160
 
                std::cerr << "HPIentry does not match this HPIfile" << std::endl;
161
 
                return 0;
162
 
        }
163
 
        if (he->directory) {
164
 
                std::cerr << "HPIentry is a directory, not a file" << std::endl;
165
 
                return 0;
166
 
        }
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);
173
 
        int j = 0;
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);
178
 
                if (sqsh->valid) {
179
 
                        j += sqsh->readall(&data[j]);
180
 
                        chunkoffset += chunksize;
181
 
                        delete sqsh;
182
 
                        delete ss;
183
 
                } else {
184
 
                        delete sqsh;
185
 
                        delete ss;
186
 
                        free(chunksizes);
187
 
                        return 0;
188
 
                }
189
 
        }
190
 
        free(chunksizes);
191
 
        return j;
192
 
}