/*---------------------------------------------------------------------------* Project: FST generator for dvd archiver File: fst.c Copyright (C) 2001-2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: fst.c,v $ Revision 1.1 2006/04/20 01:41:22 hiratsu Initial check-in. 1 7/02/01 11:34p Hashida Initial revision. $NoKeywords: $ *---------------------------------------------------------------------------*/ #include "darch.h" #include static char tmpFilePrefix[FILENAME_MAX]; int dirSearch(char* dirName, int myEntry); int stringCount; FSTEntryInfo* lastInfo; FSTEntryInfo rootEntryInfo; int entryNum; void makeTmpFileNames(void) { char* tmp; // get TMP or TEMP variable if (NULL == (tmp = getenv("TMP")) ) { if (NULL == (tmp = getenv("TEMP")) ) { tmp = "c:\\windows\\temp"; } } if (debugMode) { fprintf(stdout, "Use %s for temporary directory\n", tmp); } strcpy((void*)tmpFilePrefix, (void*)tmp); strcat((void*)tmpFilePrefix, "\\__makedisktmp__"); strcpy((void*)fstFile, (void*)tmpFilePrefix); strcat((void*)fstFile, (void*)"fst"); strcpy((void*)userFile, (void*)tmpFilePrefix); strcat((void*)userFile, (void*)"user"); } /*---------------------------------------------------------------------------* Name: dirSearch Description: search under the current directory to fill FSTEntryInfo structure. Arguments: myEntry: entry number of the directory Returns: last entry *---------------------------------------------------------------------------*/ int dirSearch(char* dirName, int myEntry) { WIN32_FIND_DATA findData; HANDLE dirHandle; BOOL result; FSTEntryInfo* currInfo; int entryCount = myEntry; int error; char nameToFind[256]; if (debugMode) { fprintf(stderr, "directory %s\n", dirName); } strcpy(nameToFind, dirName); strcat(nameToFind, "/*"); /* dummy comment for emacs */ if (debugMode) { fprintf(stderr, "Searching %s\n", nameToFind); } dirHandle = FindFirstFile(nameToFind, &findData); if (dirHandle == INVALID_HANDLE_VALUE) { fprintf(stderr, "Failed when opening %s\n", dirName); fprintf(stderr, "Error code is %d\n", GetLastError()); exit(1); } // skip . and .. (Find FirstFile already read ".") result = FindNextFile(dirHandle, &findData); // read ".." if (!result) { fprintf(stderr, "Failed when reading %s\n", dirName); fprintf(stderr, "Error code is %d\n", GetLastError()); exit(1); } while(1) { result = FindNextFile(dirHandle, &findData); if (!result) { error = GetLastError(); if (error == ERROR_NO_MORE_FILES) { // prepare to return from the function if (debugMode) { fprintf(stderr, "no more files or subdirectories in this directory\n"); } break; } else { fprintf(stderr, "Error occurred when reading directory %s\n", dirName); fprintf(stderr, "Error code is %d\n", error); exit(1); } } entryCount++; if ( NULL == (currInfo = (FSTEntryInfo*)malloc(sizeof(FSTEntryInfo))) ) { fprintf(stderr, "malloc failed\n"); exit(1); } lastInfo->next = currInfo; lastInfo = currInfo; strcpy(currInfo->pathName, dirName); strcat(currInfo->pathName, "/"); // member 'name' holds the name of file or directory w/o path currInfo->name = (char*)currInfo->pathName + strlen(currInfo->pathName); strcat(currInfo->pathName, findData.cFileName); if (debugMode) { fprintf(stderr, "name is %s\n", currInfo->name); } currInfo->nameOffset = stringCount; stringCount += ( strlen(currInfo->name) + 1 ); if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (debugMode) { fprintf(stderr, "this is a dir\n"); } currInfo->isDir = TRUE; currInfo->parentEntry = myEntry; // dirSearch returns the last entry entryCount = dirSearch(currInfo->pathName, entryCount); currInfo->nextEntry = entryCount + 1; } else { if (debugMode) { fprintf(stderr, "this is a file\n"); } currInfo->isDir = FALSE; if ( (findData.nFileSizeHigh != 0) || (findData.nFileSizeLow >= 0x80000000) ) { fprintf(stderr, "%s: File %s is too large\n", progName, currInfo->pathName); exit(1); } currInfo->fileLength = findData.nFileSizeLow; if (debugMode) { fprintf(stderr, "file length is %d\n", currInfo->fileLength); } } } if (!FindClose(dirHandle)) { fprintf(stderr, "Error occurred when closing directory %s\n", dirName); fprintf(stderr, "Error code is %d\n", GetLastError()); exit(1); } return entryCount; } /*---------------------------------------------------------------------------* Name: geography Description: rearrange file position according as geography script (not supporting geography script now) Arguments: none Returns: none *---------------------------------------------------------------------------*/ void geography(void) { FSTEntryInfo *curr; int position; position = map.userFilePosition; for(curr = &rootEntryInfo; curr; curr = curr->next) { if (curr->isDir) { continue; } position = roundUp4B(position); curr->filePosition = position; position += curr->fileLength; } map.userFileLength = position - map.userFilePosition; } void createFST(void) { void* FST; FSTEntry* currFSTEntry; FSTEntryInfo *curr; char* FSTStringStart; int i; int fid; if ( NULL == (FST = calloc(map.fstLength, 1)) ) { fprintf(stderr, "malloc failed\n"); exit(1); } currFSTEntry = (FSTEntry*)FST; FSTStringStart = (char*)(currFSTEntry + entryNum); if (debugMode) { fprintf(stderr, "entrynum is %d\n", entryNum); } curr = &rootEntryInfo; for(i = 0; i < entryNum; i++) { setIsDir(currFSTEntry, (char)curr->isDir); setStringOff(currFSTEntry, curr->nameOffset); if (debugMode) { fprintf(stderr, "pathname: %s\n", curr->pathName); fprintf(stderr, "name: %s\n", curr->name); fprintf(stderr, "nameoffset: %d\n", curr->nameOffset); } strcpy( (void*)(FSTStringStart + curr->nameOffset), (void*)curr->name ); if (curr->isDir) { setParent(currFSTEntry, curr->parentEntry); setNextEntry(currFSTEntry, curr->nextEntry); } else { setPosition(currFSTEntry, curr->filePosition); setLength(currFSTEntry, curr->fileLength); } curr = curr->next; currFSTEntry++; } if (debugMode) { fprintf(stderr, "fst file name is %s\n", fstFile); } if( (fid = open(fstFile, O_BINARY | O_TRUNC | O_CREAT | O_WRONLY, 0666)) == -1 ) { fprintf(stderr, "error opening an fst file\n"); exit(1); } if (map.fstLength != write(fid, FST, map.fstLength)) { fprintf(stderr, "error writing file\n"); exit(1); } if (close(fid) == -1) { fprintf(stderr, "error closing file\n"); exit(1); } // Free FST free(FST); } void createUserFile(void) { FSTEntryInfo *curr; int fids; int fidd; if (debugMode) { fprintf(stderr, "userfileLength is 0x%08x\n", map.userFileLength); } if( (fidd = open(userFile, O_TRUNC | O_CREAT | O_BINARY | O_WRONLY, 0666)) == -1 ) { fprintf(stderr, "error opening user file\n"); exit(1); } for(curr = &rootEntryInfo; curr; curr = curr->next) { if (curr->isDir) { if (verbose) { fprintf(stdout, "%s", curr->pathName); fprintf(stdout, "/\n"); } continue; } if (verbose) { fprintf(stdout, "%s", curr->pathName); fprintf(stdout, "\n"); } // read the file into the position where already decided if( (fids = open(curr->pathName, O_BINARY | O_RDONLY)) == -1 ) { fprintf(stderr, "error opening %s\n", curr->pathName); exit(1); } CopyUtility(fids, 0, fidd, curr->filePosition - map.userFilePosition, curr->fileLength); if (close(fids) == -1) { fprintf(stderr, "error closing %s\n", curr->pathName); exit(1); } } if (close(fidd) == -1) { fprintf(stderr, "error closing user file\n"); exit(1); } } int makeFST(void) { FSTEntryInfo *curr; FSTEntryInfo *next; strcpy(rootEntryInfo.pathName, ""); rootEntryInfo.name = rootEntryInfo.pathName; rootEntryInfo.nameOffset = 0; rootEntryInfo.isDir = TRUE; rootEntryInfo.parentEntry = 0; lastInfo = &rootEntryInfo; entryNum = dirSearch(arcRoot, 0) + 1; rootEntryInfo.nextEntry = entryNum; lastInfo->next = NULL; // end mark if (debugMode) { fprintf(stderr, "finished making FST\n"); fprintf(stderr, "size of fstentry is %d\n", sizeof(FSTEntry)); } map.fstLength = sizeof(FSTEntry) * entryNum + stringCount; map.fstPosition = sizeof(ARCHeader); map.userFilePosition = roundUp4B(map.fstPosition + map.fstLength); // special solution; we put fst size here // rootEntryInfo.parentEntry = map.fstLength; geography(); createFST(); createUserFile(); // Free each FSTEntryInfo structures for (next = rootEntryInfo.next; next != NULL; ) { curr = next; next = curr->next; free((void*)curr); } return 0; }