1 /*---------------------------------------------------------------------------*
2 Project: FST generator for dvd archiver
3 File: fst.c
4
5 Copyright (C) 2001-2006 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: fst.c,v $
14 Revision 1.1 2006/04/20 01:41:22 hiratsu
15 Initial check-in.
16
17
18 1 7/02/01 11:34p Hashida
19 Initial revision.
20
21 $NoKeywords: $
22 *---------------------------------------------------------------------------*/
23
24 #include "darch.h"
25 #include <Windows.h>
26
27
28 static char tmpFilePrefix[FILENAME_MAX];
29
30 int dirSearch(char* dirName, int myEntry);
31
32 int stringCount;
33 FSTEntryInfo* lastInfo;
34 FSTEntryInfo rootEntryInfo;
35 int entryNum;
36
makeTmpFileNames(void)37 void makeTmpFileNames(void)
38 {
39 char* tmp;
40
41 // get TMP or TEMP variable
42 if (NULL == (tmp = getenv("TMP")) )
43 {
44 if (NULL == (tmp = getenv("TEMP")) )
45 {
46 tmp = "c:\\windows\\temp";
47 }
48 }
49
50 if (debugMode)
51 {
52 fprintf(stdout, "Use %s for temporary directory\n", tmp);
53 }
54
55 strcpy((void*)tmpFilePrefix, (void*)tmp);
56 strcat((void*)tmpFilePrefix, "\\__makedisktmp__");
57
58 strcpy((void*)fstFile, (void*)tmpFilePrefix);
59 strcat((void*)fstFile, (void*)"fst");
60
61 strcpy((void*)userFile, (void*)tmpFilePrefix);
62 strcat((void*)userFile, (void*)"user");
63 }
64
65 /*---------------------------------------------------------------------------*
66 Name: dirSearch
67
68 Description: search under the current directory to fill FSTEntryInfo
69 structure.
70
71 Arguments: myEntry: entry number of the directory
72
73 Returns: last entry
74 *---------------------------------------------------------------------------*/
dirSearch(char * dirName,int myEntry)75 int dirSearch(char* dirName, int myEntry)
76 {
77 WIN32_FIND_DATA findData;
78 HANDLE dirHandle;
79 BOOL result;
80 FSTEntryInfo* currInfo;
81 int entryCount = myEntry;
82 int error;
83 char nameToFind[256];
84
85 if (debugMode)
86 {
87 fprintf(stderr, "directory %s\n", dirName);
88 }
89
90
91 strcpy(nameToFind, dirName);
92 strcat(nameToFind, "/*"); /* dummy comment for emacs */
93
94 if (debugMode)
95 {
96 fprintf(stderr, "Searching %s\n", nameToFind);
97 }
98
99 dirHandle = FindFirstFile(nameToFind, &findData);
100 if (dirHandle == INVALID_HANDLE_VALUE)
101 {
102 fprintf(stderr, "Failed when opening %s\n", dirName);
103 fprintf(stderr, "Error code is %d\n", GetLastError());
104 exit(1);
105 }
106
107 // skip . and .. (Find FirstFile already read ".")
108 result = FindNextFile(dirHandle, &findData); // read ".."
109 if (!result)
110 {
111 fprintf(stderr, "Failed when reading %s\n", dirName);
112 fprintf(stderr, "Error code is %d\n", GetLastError());
113 exit(1);
114 }
115
116 while(1)
117 {
118 result = FindNextFile(dirHandle, &findData);
119
120 if (!result)
121 {
122 error = GetLastError();
123
124 if (error == ERROR_NO_MORE_FILES)
125 {
126 // prepare to return from the function
127 if (debugMode)
128 {
129 fprintf(stderr, "no more files or subdirectories in this directory\n");
130 }
131 break;
132 }
133 else
134 {
135 fprintf(stderr, "Error occurred when reading directory %s\n",
136 dirName);
137 fprintf(stderr, "Error code is %d\n", error);
138 exit(1);
139 }
140 }
141 entryCount++;
142
143 if ( NULL == (currInfo = (FSTEntryInfo*)malloc(sizeof(FSTEntryInfo))) )
144 {
145 fprintf(stderr, "malloc failed\n");
146 exit(1);
147 }
148 lastInfo->next = currInfo;
149 lastInfo = currInfo;
150
151 strcpy(currInfo->pathName, dirName);
152 strcat(currInfo->pathName, "/");
153
154 // member 'name' holds the name of file or directory w/o path
155 currInfo->name = (char*)currInfo->pathName
156 + strlen(currInfo->pathName);
157 strcat(currInfo->pathName, findData.cFileName);
158
159 if (debugMode)
160 {
161 fprintf(stderr, "name is %s\n", currInfo->name);
162 }
163
164 currInfo->nameOffset = stringCount;
165
166 stringCount += ( strlen(currInfo->name) + 1 );
167
168 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
169 {
170 if (debugMode)
171 {
172 fprintf(stderr, "this is a dir\n");
173 }
174
175 currInfo->isDir = TRUE;
176 currInfo->parentEntry = myEntry;
177
178 // dirSearch returns the last entry
179 entryCount = dirSearch(currInfo->pathName, entryCount);
180
181 currInfo->nextEntry = entryCount + 1;
182 }
183 else
184 {
185 if (debugMode)
186 {
187 fprintf(stderr, "this is a file\n");
188 }
189
190 currInfo->isDir = FALSE;
191
192 if ( (findData.nFileSizeHigh != 0) ||
193 (findData.nFileSizeLow >= 0x80000000) )
194 {
195 fprintf(stderr, "%s: File %s is too large\n", progName,
196 currInfo->pathName);
197 exit(1);
198 }
199 currInfo->fileLength = findData.nFileSizeLow;
200
201 if (debugMode)
202 {
203 fprintf(stderr, "file length is %d\n", currInfo->fileLength);
204 }
205
206 }
207
208 }
209
210 if (!FindClose(dirHandle))
211 {
212 fprintf(stderr, "Error occurred when closing directory %s\n",
213 dirName);
214 fprintf(stderr, "Error code is %d\n", GetLastError());
215 exit(1);
216 }
217
218 return entryCount;
219 }
220
221
222 /*---------------------------------------------------------------------------*
223 Name: geography
224
225 Description: rearrange file position according as geography script
226 (not supporting geography script now)
227
228 Arguments: none
229
230 Returns: none
231 *---------------------------------------------------------------------------*/
geography(void)232 void geography(void)
233 {
234 FSTEntryInfo *curr;
235 int position;
236
237 position = map.userFilePosition;
238
239 for(curr = &rootEntryInfo; curr; curr = curr->next)
240 {
241 if (curr->isDir)
242 {
243 continue;
244 }
245
246 position = roundUp4B(position);
247 curr->filePosition = position;
248
249 position += curr->fileLength;
250 }
251
252 map.userFileLength = position - map.userFilePosition;
253 }
254
255
createFST(void)256 void createFST(void)
257 {
258 void* FST;
259 FSTEntry* currFSTEntry;
260 FSTEntryInfo *curr;
261 char* FSTStringStart;
262 int i;
263 int fid;
264
265
266 if ( NULL == (FST = calloc(map.fstLength, 1)) )
267 {
268 fprintf(stderr, "malloc failed\n");
269 exit(1);
270 }
271 currFSTEntry = (FSTEntry*)FST;
272 FSTStringStart = (char*)(currFSTEntry + entryNum);
273
274 if (debugMode)
275 {
276 fprintf(stderr, "entrynum is %d\n", entryNum);
277 }
278
279 curr = &rootEntryInfo;
280 for(i = 0; i < entryNum; i++)
281 {
282 setIsDir(currFSTEntry, (char)curr->isDir);
283
284 setStringOff(currFSTEntry, curr->nameOffset);
285
286 if (debugMode)
287 {
288 fprintf(stderr, "pathname: %s\n", curr->pathName);
289 fprintf(stderr, "name: %s\n", curr->name);
290 fprintf(stderr, "nameoffset: %d\n", curr->nameOffset);
291 }
292
293 strcpy( (void*)(FSTStringStart + curr->nameOffset),
294 (void*)curr->name );
295
296 if (curr->isDir)
297 {
298 setParent(currFSTEntry, curr->parentEntry);
299 setNextEntry(currFSTEntry, curr->nextEntry);
300 }
301 else
302 {
303 setPosition(currFSTEntry, curr->filePosition);
304 setLength(currFSTEntry, curr->fileLength);
305
306 }
307
308 curr = curr->next;
309 currFSTEntry++;
310 }
311
312 if (debugMode)
313 {
314 fprintf(stderr, "fst file name is %s\n", fstFile);
315 }
316
317 if( (fid = open(fstFile, O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1 )
318 {
319 fprintf(stderr, "error opening an fst file\n");
320 exit(1);
321 }
322
323 if (map.fstLength != write(fid, FST, map.fstLength))
324 {
325 fprintf(stderr, "error writing file\n");
326 exit(1);
327 }
328
329 if (close(fid) == -1)
330 {
331 fprintf(stderr, "error closing file\n");
332 exit(1);
333 }
334
335 // Free FST
336 free(FST);
337
338 }
339
createUserFile(void)340 void createUserFile(void)
341 {
342 FSTEntryInfo *curr;
343 int fids;
344 int fidd;
345
346
347 if (debugMode)
348 {
349 fprintf(stderr, "userfileLength is 0x%08x\n", map.userFileLength);
350 }
351
352 if( (fidd = open(userFile, O_TRUNC | O_CREAT | O_BINARY | O_WRONLY, 0666)) == -1 )
353 {
354 fprintf(stderr, "error opening user file\n");
355 exit(1);
356 }
357
358 for(curr = &rootEntryInfo; curr; curr = curr->next)
359 {
360 if (curr->isDir)
361 {
362 if (verbose)
363 {
364 fprintf(stdout, "%s", curr->pathName);
365 fprintf(stdout, "/\n");
366 }
367 continue;
368 }
369
370 if (verbose)
371 {
372 fprintf(stdout, "%s", curr->pathName);
373 fprintf(stdout, "\n");
374 }
375
376 // read the file into the position where already decided
377 if( (fids = open(curr->pathName, O_BINARY | O_RDONLY)) == -1 )
378 {
379 fprintf(stderr, "error opening %s\n", curr->pathName);
380 exit(1);
381 }
382
383 CopyUtility(fids, 0,
384 fidd, curr->filePosition - map.userFilePosition,
385 curr->fileLength);
386
387 if (close(fids) == -1)
388 {
389 fprintf(stderr, "error closing %s\n", curr->pathName);
390 exit(1);
391 }
392 }
393
394 if (close(fidd) == -1)
395 {
396 fprintf(stderr, "error closing user file\n");
397 exit(1);
398 }
399
400 }
401
402
makeFST(void)403 int makeFST(void)
404 {
405 FSTEntryInfo *curr;
406 FSTEntryInfo *next;
407
408
409 strcpy(rootEntryInfo.pathName, "");
410 rootEntryInfo.name = rootEntryInfo.pathName;
411 rootEntryInfo.nameOffset = 0;
412 rootEntryInfo.isDir = TRUE;
413 rootEntryInfo.parentEntry = 0;
414
415 lastInfo = &rootEntryInfo;
416
417 entryNum = dirSearch(arcRoot, 0) + 1;
418 rootEntryInfo.nextEntry = entryNum;
419
420 lastInfo->next = NULL; // end mark
421
422 if (debugMode)
423 {
424 fprintf(stderr, "finished making FST\n");
425 fprintf(stderr, "size of fstentry is %d\n", sizeof(FSTEntry));
426 }
427
428 map.fstLength = sizeof(FSTEntry) * entryNum + stringCount;
429 map.fstPosition = sizeof(ARCHeader);
430 map.userFilePosition = roundUp4B(map.fstPosition + map.fstLength);
431
432 // special solution; we put fst size here
433 // rootEntryInfo.parentEntry = map.fstLength;
434
435 geography();
436
437 createFST();
438
439 createUserFile();
440
441 // Free each FSTEntryInfo structures
442 for (next = rootEntryInfo.next; next != NULL; )
443 {
444 curr = next;
445 next = curr->next;
446 free((void*)curr);
447 }
448
449 return 0;
450 }
451