/* * A Z-Machine * Copyright (C) 2000 Andrew Hunter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Deal with files */ #include "../config.h" #include #include #include #include #include #include "file.h" #include "zmachine.h" #if WINDOW_SYSTEM != 2 && WINDOW_SYSTEM != 3 && WINDOW_SYSTEM != 4 struct ZFile { FILE* handle; }; ZFile* open_file(char* filename) { ZFile* res; res = malloc(sizeof(ZFile)); res->handle = fopen(filename, "r"); if (res->handle == NULL) { free(res); return NULL; } return res; } ZFile* open_file_write(char* filename) { ZFile* res; res = malloc(sizeof(ZFile)); res->handle = fopen(filename, "w"); if (res->handle == NULL) { free(res); return NULL; } return res; } void close_file(ZFile* file) { fclose(file->handle); free(file); } ZByte* read_page(ZFile* file, int page_no) { ZByte* page; page = malloc(4096); if (page == NULL) return NULL; fseek(file->handle, 4096*page_no, SEEK_SET); fread(page, 4096, 1, file->handle); return page; } ZByte* read_block(ZFile* file, int start_pos, int end_pos) { ZByte* block; size_t rd; block = malloc(end_pos-start_pos); if (block == NULL) return NULL; if (fseek(file->handle, start_pos, SEEK_SET)) zmachine_fatal("Failed to seek to position %i", start_pos); rd = fread(block, 1, end_pos-start_pos, file->handle); if (rd != end_pos-start_pos) zmachine_fatal("Tried to read %i items of 1 byte, got %i items", end_pos-start_pos, rd); return block; } ZByte inline read_byte(ZFile* file) { return fgetc(file->handle); } ZUWord read_word(ZFile* file) { return (read_byte(file)<<8)|read_byte(file); } ZUWord read_rword(ZFile* file) { return read_byte(file)|(read_byte(file)<<8); } void read_block2(ZByte* block, ZFile* file, int start_pos, int end_pos) { fseek(file->handle, start_pos, SEEK_SET); fread(block, end_pos-start_pos, 1, file->handle); } ZDWord get_file_size(char* filename) { struct stat buf; if (stat(filename, &buf) != 0) { return -1; } return buf.st_size; } int end_of_file(ZFile* file) { return feof(file->handle)!=0; } void write_block(ZFile* file, ZByte* block, int length) { fwrite(block, 1, length, file->handle); } inline void write_byte(ZFile* file, ZByte byte) { fputc(byte, file->handle); } void write_word(ZFile* file, ZWord word) { write_byte(file, word>>8); write_byte(file, word); } void write_dword(ZFile* file, ZDWord word) { write_byte(file, word>>24); write_byte(file, word>>16); write_byte(file, word>>8); write_byte(file, word); } #elif WINDOW_SYSTEM == 2 #include struct ZFile { HANDLE file; }; ZFile* open_file(char* filename) { ZFile* f; f = malloc(sizeof(ZFile)); f->file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (f->file == INVALID_HANDLE_VALUE) { free(f); return NULL; } return f; } ZFile* open_file_write(char* filename) { ZFile* f; f = malloc(sizeof(ZFile)); f->file = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (f->file == INVALID_HANDLE_VALUE) { free(f); return NULL; } return f; } void close_file(ZFile* file) { CloseHandle(file->file); free(file); } ZByte read_byte(ZFile* file) { ZByte block[1]; DWORD nread; if (!ReadFile(file->file, block, 1, &nread, NULL)) zmachine_fatal("Unable to read byte from file"); return block[0]; } ZUWord read_word(ZFile* file) { return (read_byte(file)<<8)|read_byte(file); } ZUWord read_rword(ZFile* file) { return read_byte(file)|(read_byte(file)<<8); } ZByte* read_block(ZFile* file, int start_pos, int end_pos) { ZByte* block; DWORD nread; block = malloc(sizeof(ZByte)*(end_pos-start_pos)); if (SetFilePointer(file->file, start_pos, NULL, FILE_BEGIN) == -1) { zmachine_fatal("Unable to seek to %i", start_pos); free(block); return NULL; } if (!ReadFile(file->file, block, end_pos-start_pos, &nread, NULL)) { zmachine_fatal("Unable to read %i bytes", end_pos-start_pos); free(block); return NULL; } if (nread != end_pos-start_pos) { zmachine_fatal("Tried to read %i bytes, but only got %i", end_pos-start_pos, nread); free(block); return NULL; } return block; } void read_block2(ZByte* block, ZFile* file, int start_pos, int end_pos) { DWORD nread; if (SetFilePointer(file->file, start_pos, NULL, FILE_BEGIN) == -1) zmachine_fatal("Unable to seek"); if (!ReadFile(file->file, block, end_pos-start_pos, &nread, NULL)) zmachine_fatal("Unable to read file"); if (nread != end_pos-start_pos) zmachine_fatal("Tried to read %i bytes, but only got %i", end_pos-start_pos, nread); } void write_block(ZFile* file, ZByte* block, int length) { DWORD nwrite; WriteFile(file->file, block, length, &nwrite, NULL); } void write_byte(ZFile* file, ZByte byte) { write_block(file, &byte, 1); } void write_word(ZFile* file, ZWord word) { write_byte(file, word>>8); write_byte(file, word); } void write_dword(ZFile* file, ZDWord word) { write_byte(file, word>>24); write_byte(file, word>>16); write_byte(file, word>>8); write_byte(file, word); } ZDWord get_file_size(char* filename) { HANDLE hnd; ZDWord sz; hnd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hnd == INVALID_HANDLE_VALUE) return -1; sz = GetFileSize(hnd, NULL); CloseHandle(hnd); return sz; } /* end_of_file not implemented: implement to fix the Windows port */ #elif WINDOW_SYSTEM == 3 /* Mac OS file handling functions */ #include #include "carbondisplay.h" /* * We add a couple of functions to deal with opening files straight from * FSRefs */ struct ZFile { FSRef fileref; SInt16 forkref; int endOfFile; }; static char* file_error_text(OSStatus stat) { switch (stat) { case notOpenErr: return "Volume not found"; case dirFulErr: return "Directory full"; case dskFulErr: return "Disk full"; case nsvErr: return "Volume not found"; case ioErr: return "I/O error"; case bdNamErr: return "Bad filename"; case fnOpnErr: return "File not open"; case eofErr: return "End of file"; case posErr: return "Bad file position"; case tmfoErr: return "Too many files open"; case fnfErr: return "File not found"; case wPrErr: case vLckdErr: return "Volume locked"; case fLckdErr: return "File locked"; case fBsyErr: return "File busy"; case rfNumErr: return "Invalid reference number"; default: { static char str[255]; sprintf(str, "Unknown reason code - %i", (int) stat); return str; } } } ZFile* open_file(char* filename) { FSRef ref; FSPathMakeRef(filename, &ref, NULL); return open_file_fsref(&ref); } ZFile* open_file_write(char* filename) { FSRef ref; FSSpec spec; OSStatus erm; FInfo inf; int x; char* dirname; UniChar* uniname; int lastslash = -1; FSRef parent; erm = FSPathMakeRef(filename, &ref, NULL); if (erm != fnfErr) { erm = FSDeleteObject(&ref); if (erm != noErr) return NULL; } dirname = malloc(strlen(filename)+1); uniname = malloc((strlen(filename)+1)*sizeof(int)); strcpy(dirname, filename); for (x=0; filename[x] != 0; x++) { uniname[x] = filename[x]; if (filename[x] == '/') lastslash = x; } uniname[x] = 0; if (lastslash == -1) { free(dirname); free(uniname); return NULL; } dirname[lastslash] = 0; erm = FSPathMakeRef(dirname, &parent, NULL); if (erm != NULL) { free(dirname); free(uniname); return NULL; } erm = FSCreateFileUnicode(&parent, strlen(filename) - lastslash-1, uniname + lastslash + 1, kFSCatInfoNone, NULL, &ref, &spec); if (erm != noErr) { free(dirname); free(uniname); return NULL; } free(dirname); free(uniname); FSpGetFInfo(&spec, &inf); inf.fdType = 'BINA'; inf.fdCreator = SIGNATURE; FSpSetFInfo(&spec, &inf); return open_file_write_fsref(&ref); } ZFile* open_file_fsref(FSRef* ref) { HFSUniStr255 dfork; ZFile *file; SInt16 refnum; OSErr erm; FSGetDataForkName(&dfork); erm = FSOpenFork(ref, dfork.length, dfork.unicode, fsRdPerm, &refnum); if (erm != noErr) return NULL; file = malloc(sizeof(ZFile)); file->fileref = *ref; file->forkref = refnum; file->endOfFile = 0; return file; } ZFile* open_file_write_fsref(FSRef* ref) { HFSUniStr255 dfork; ZFile *file; SInt16 refnum; OSErr erm; FSGetDataForkName(&dfork); erm = FSOpenFork(ref, dfork.length, dfork.unicode, fsWrPerm, &refnum); if (erm != noErr) return NULL; file = malloc(sizeof(ZFile)); file->fileref = *ref; file->forkref = refnum; file->endOfFile = 0; return file; } FSRef get_file_fsref(ZFile* file) { return file->fileref; } void close_file(ZFile* file) { FSCloseFork(file->forkref); free(file); } ZByte* read_page(ZFile* file, int page_no) { return read_block(file, 4096*page_no, 4096*page_no+4096); } ZByte* read_block(ZFile* file, int start_pos, int end_pos) { ZByte* block; OSStatus erm; ByteCount rd; block = malloc(end_pos-start_pos); if (block == NULL) return NULL; erm = FSReadFork(file->forkref, fsFromStart, start_pos, end_pos-start_pos, block, &rd); if (erm != noErr) zmachine_fatal("Error while reading from file - %s", file_error_text(erm)); if (erm == eofErr) endOfFile = 1; if (rd != end_pos-start_pos) zmachine_fatal("Tried to read %i items of 1 byte, got %i items", end_pos-start_pos, rd); return block; } ZByte inline read_byte(ZFile* file) { char byte; OSErr res; res = FSReadFork(file->forkref, fsAtMark, 0, 1, &byte, NULL); if (res == eofErr) file->endOfFile = 1; return byte; } ZUWord read_word(ZFile* file) { return (read_byte(file)<<8)|read_byte(file); } ZUWord read_rword(ZFile* file) { return read_byte(file)|(read_byte(file)<<8); } void read_block2(ZByte* block, ZFile* file, int start_pos, int end_pos) { OSErr erm; erm = FSReadFork(file->forkref, fsFromStart, start_pos, end_pos-start_pos, block, NULL); if (erm == eofErr) file->endOfFile = 1; } ZDWord get_file_size(char* filename) { FSRef ref; OSStatus res; res = FSPathMakeRef(filename, &ref, NULL); if (res != noErr) return -1; return get_file_size_fsref(&ref); } int end_of_file(ZFile* file) { return file->endOfFile; } ZDWord get_file_size_fsref(FSRef* file) { FSCatalogInfo inf; FSGetCatalogInfo(file, kFSCatInfoDataSizes, &inf, NULL, NULL, NULL); return inf.dataLogicalSize; } void write_block(ZFile* file, ZByte* block, int length) { FSWriteFork(file->forkref, fsAtMark, 0, length, block, NULL); } inline void write_byte(ZFile* file, ZByte byte) { FSWriteFork(file->forkref, fsAtMark, 0, 1, &byte, NULL); } void write_word(ZFile* file, ZWord word) { write_byte(file, word>>8); write_byte(file, word); } void write_dword(ZFile* file, ZDWord word) { write_byte(file, word>>24); write_byte(file, word>>16); write_byte(file, word>>8); write_byte(file, word); } #endif void write_string(ZFile* file, const char* string) { write_block(file, (unsigned char*)string, strlen(string)); } void write_stringf(ZFile* file, const char* format, ...) { char buffer[4096]; va_list ap; va_start(ap, format); vsnprintf(buffer, 4096, format, ap); buffer[4095] = 0; va_end(ap); write_string(file, buffer); } void write_stringu(ZFile* file, const int* string) { /* Maybe FIXME: write in UTF-8 format? */ int len, x; char* str; for (len=0; string[len] != 0; len++); str = malloc(len+1); for (x=0; x