1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "KEYImporter.h"
24 #include "FileStream.h"
25 #include "Interface.h"
26 #include "ArchiveImporter.h"
27 #include "ResourceDesc.h"
32 #define SHARED_OVERRIDE "shared"
34 KEYImporter::KEYImporter(void)
38 KEYImporter::~KEYImporter(void)
40 for (unsigned int i
= 0; i
< biffiles
.size(); i
++) {
41 free( biffiles
[i
].name
);
45 static bool exists(char *file
)
47 FILE *f
= fopen( file
, "rb" );
55 static void FindBIF(BIFEntry
*entry
)
59 PathJoin( entry
->path
, core
->GamePath
, entry
->name
, NULL
);
60 ResolveFilePath(entry
->path
);
61 if (exists(entry
->path
)) {
66 PathJoin( entry
->path
, core
->GamePath
, entry
->name
, NULL
);
67 strcpy( entry
->path
+ strlen( entry
->path
) - 4, ".cbf" );
68 ResolveFilePath(entry
->path
);
69 if (exists(entry
->path
)) {
75 char BasePath
[_MAX_PATH
];
76 if (( entry
->BIFLocator
& ( 1 << 2 ) ) != 0) {
77 strcpy( BasePath
, core
->CD
[0] );
79 } else if (( entry
->BIFLocator
& ( 1 << 3 ) ) != 0) {
80 strcpy( BasePath
, core
->CD
[1] );
82 } else if (( entry
->BIFLocator
& ( 1 << 4 ) ) != 0) {
83 strcpy( BasePath
, core
->CD
[2] );
85 } else if (( entry
->BIFLocator
& ( 1 << 5 ) ) != 0) {
86 strcpy( BasePath
, core
->CD
[3] );
88 } else if (( entry
->BIFLocator
& ( 1 << 6 ) ) != 0) {
89 strcpy( BasePath
, core
->CD
[4] );
92 printStatus( "ERROR", LIGHT_RED
);
93 printf( "Cannot find %s... Resource unavailable.\n",
98 PathJoin( entry
->path
, BasePath
, entry
->name
, NULL
);
103 for (int i
= 0; i
< 6; i
++) {
104 PathJoin( entry
->path
, core
->CD
[i
], entry
->name
, NULL
);
105 ResolveFilePath(entry
->path
);
106 if (exists(entry
->path
)) {
111 //Trying CBF Extension
112 PathJoin( entry
->path
, core
->CD
[i
], entry
->name
, NULL
);
113 strcpy( entry
->path
+ strlen( entry
->path
) - 4, ".cbf" );
114 ResolveFilePath(entry
->path
);
115 if (exists(entry
->path
)) {
121 printMessage( "KEYImporter", " ", WHITE
);
122 printf( "Cannot find %s...", entry
->name
);
123 printStatus( "ERROR", LIGHT_RED
);
124 entry
->found
= false;
127 bool KEYImporter::Open(const char *resfile
, const char *desc
)
130 if (!core
->IsAvailable( IE_BIF_CLASS_ID
)) {
131 printf( "[ERROR]\nAn Archive Plug-in is not Available\n" );
135 // NOTE: Interface::Init has already resolved resfile.
136 printMessage( "KEYImporter", "Opening ", WHITE
);
137 printf( "%s...", resfile
);
138 FileStream
* f
= new FileStream();
139 if (!f
->Open( resfile
)) {
140 printStatus( "ERROR", LIGHT_RED
);
141 printMessage( "KEYImporter", "Cannot open Chitin.key\n", LIGHT_RED
);
146 printStatus( "OK", LIGHT_GREEN
);
147 printMessage( "KEYImporter", "Checking file type...", WHITE
);
149 f
->Read( Signature
, 8 );
150 if (strncmp( Signature
, "KEY V1 ", 8 ) != 0) {
151 printStatus( "ERROR", LIGHT_RED
);
152 printMessage( "KEYImporter", "File has an Invalid Signature.\n",
158 printStatus( "OK", LIGHT_GREEN
);
159 printMessage( "KEYImporter", "Reading Resources...\n", WHITE
);
160 ieDword BifCount
, ResCount
, BifOffset
, ResOffset
;
161 f
->ReadDword( &BifCount
);
162 f
->ReadDword( &ResCount
);
163 f
->ReadDword( &BifOffset
);
164 f
->ReadDword( &ResOffset
);
165 printMessage( "KEYImporter", " ", WHITE
);
166 printf( "BIF Files Count: %d (Starting at %d Bytes)\n", BifCount
,
168 printMessage( "KEYImporter", " ", WHITE
);
169 printf( "RES Count: %d (Starting at %d Bytes)\n", ResCount
, ResOffset
);
170 f
->Seek( BifOffset
, GEM_STREAM_START
);
171 ieDword BifLen
, ASCIIZOffset
;
173 for (i
= 0; i
< BifCount
; i
++) {
175 f
->Seek( BifOffset
+ ( 12 * i
), GEM_STREAM_START
);
176 f
->ReadDword( &BifLen
);
177 f
->ReadDword( &ASCIIZOffset
);
178 f
->ReadWord( &ASCIIZLen
);
179 f
->ReadWord( &be
.BIFLocator
);
180 be
.name
= ( char * ) malloc( ASCIIZLen
);
181 f
->Seek( ASCIIZOffset
, GEM_STREAM_START
);
182 f
->Read( be
.name
, ASCIIZLen
);
184 for (int p
= 0; p
< ASCIIZLen
; p
++) {
185 //some MAC versions use : as delimiter
186 if (be
.name
[p
] == '\\' || be
.name
[p
] == ':')
187 be
.name
[p
] = PathDelimiter
;
189 if (be
.name
[0] == PathDelimiter
) {
190 // totl has '\data\zcMHar.bif' in the key file, and the CaseSensitive
191 // code breaks with that extra slash, so simple fix: remove it
193 for (int p
= 0; p
< ASCIIZLen
; p
++)
194 be
.name
[p
] = be
.name
[p
+ 1];
195 // (if you change this, try moving to ar9700 for testing)
199 biffiles
.push_back( be
);
201 f
->Seek( ResOffset
, GEM_STREAM_START
);
202 resources
.InitHashTable( ResCount
< 17 ? 17 : ResCount
);
203 for (i
= 0; i
< ResCount
; i
++) {
205 f
->ReadResRef( re
.ResRef
);
206 f
->ReadWord( &re
.Type
);
207 f
->ReadDword( &re
.ResLocator
);
208 resources
.SetAt( re
.ResRef
, re
.Type
, re
.ResLocator
);
210 printMessage( "KEYImporter", "Resources Loaded...", WHITE
);
211 printStatus( "OK", LIGHT_GREEN
);
216 bool KEYImporter::HasResource(const char* resname
, SClass_ID type
)
218 unsigned int ResLocator
;
219 return resources
.Lookup( resname
, type
, ResLocator
);
222 bool KEYImporter::HasResource(const char* resname
, const ResourceDesc
&type
)
224 return HasResource(resname
, type
.GetKeyType());
227 static void FindBIFOnCD(BIFEntry
*entry
)
229 ResolveFilePath(entry
->path
);
230 if (exists(entry
->path
)) {
235 core
->WaitForDisc( entry
->cd
, core
->CD
[entry
->cd
-1] );
236 ResolveFilePath(entry
->path
);
237 if (exists(entry
->path
)) {
242 //Trying CBF Extension
243 strcpy( entry
->path
+ strlen( entry
->path
) - 4, ".cbf" );
244 ResolveFilePath(entry
->path
);
245 if (exists(entry
->path
)) {
250 entry
->found
= false;
253 DataStream
* KEYImporter::GetStream(const char *resname
, ieWord type
)
255 unsigned int ResLocator
;
259 if (resources
.Lookup( resname
, type
, ResLocator
)) {
260 int bifnum
= ( ResLocator
& 0xFFF00000 ) >> 20;
262 if (core
->GameOnCD
&& (biffiles
[bifnum
].cd
!= 0))
263 FindBIFOnCD(&biffiles
[bifnum
]);
264 if (!biffiles
[bifnum
].found
) {
265 printf( "Cannot find %s... Resource unavailable.\n",
266 biffiles
[bifnum
].name
);
270 ArchiveImporter
* ai
= ( ArchiveImporter
* )
271 core
->GetInterface( IE_BIF_CLASS_ID
);
272 if (ai
->OpenArchive( biffiles
[bifnum
].path
) == GEM_ERROR
) {
273 printf("Cannot open archive %s\n", biffiles
[bifnum
].path
);
274 core
->FreeInterface( ai
);
277 DataStream
* ret
= ai
->GetStream( ResLocator
, type
);
278 core
->FreeInterface( ai
);
280 strnlwrcpy( ret
->filename
, resname
, 8 );
281 strcat( ret
->filename
, core
->TypeExt( type
) );
288 DataStream
* KEYImporter::GetResource(const char* resname
, SClass_ID type
)
290 //the word masking is a hack for synonyms, currently used for bcs==bs
291 return GetStream(resname
, type
&0xFFFF);
294 DataStream
* KEYImporter::GetResource(const char* resname
, const ResourceDesc
&type
)
296 return GetStream(resname
, type
.GetKeyType());
299 #include "plugindef.h"
301 GEMRB_PLUGIN(0x1DFDEF80, "KEY File Importer")
302 PLUGIN_CLASS(PLUGIN_RESOURCE_KEY
, KEYImporter
)