1 /*
2 * A Z-Machine
3 * Copyright (C) 2000 Andrew Hunter
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * Deal with files
22 */
23
24 #include "../config.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <sys/stat.h>
31
32 #include "file.h"
33 #include "zmachine.h"
34
35 #if WINDOW_SYSTEM != 2 && WINDOW_SYSTEM != 3 && WINDOW_SYSTEM != 4
36
37 struct ZFile
38 {
39 FILE* handle;
40 };
41
open_file(char * filename)42 ZFile* open_file(char* filename)
43 {
44 ZFile* res;
45
46 res = malloc(sizeof(ZFile));
47 res->handle = fopen(filename, "r");
48
49 if (res->handle == NULL)
50 {
51 free(res);
52 return NULL;
53 }
54
55 return res;
56 }
57
open_file_write(char * filename)58 ZFile* open_file_write(char* filename)
59 {
60 ZFile* res;
61
62 res = malloc(sizeof(ZFile));
63 res->handle = fopen(filename, "w");
64
65 if (res->handle == NULL)
66 {
67 free(res);
68 return NULL;
69 }
70
71 return res;
72 }
73
close_file(ZFile * file)74 void close_file(ZFile* file)
75 {
76 fclose(file->handle);
77 free(file);
78 }
79
read_page(ZFile * file,int page_no)80 ZByte* read_page(ZFile* file, int page_no)
81 {
82 ZByte* page;
83
84 page = malloc(4096);
85 if (page == NULL)
86 return NULL;
87
88 fseek(file->handle, 4096*page_no, SEEK_SET);
89 fread(page, 4096, 1, file->handle);
90
91 return page;
92 }
93
read_block(ZFile * file,int start_pos,int end_pos)94 ZByte* read_block(ZFile* file, int start_pos, int end_pos)
95 {
96 ZByte* block;
97 size_t rd;
98
99 block = malloc(end_pos-start_pos);
100 if (block == NULL)
101 return NULL;
102
103 if (fseek(file->handle, start_pos, SEEK_SET))
104 zmachine_fatal("Failed to seek to position %i", start_pos);
105 rd = fread(block, 1, end_pos-start_pos, file->handle);
106 if (rd != end_pos-start_pos)
107 zmachine_fatal("Tried to read %i items of 1 byte, got %i items",
108 end_pos-start_pos, rd);
109
110 return block;
111 }
112
read_byte(ZFile * file)113 ZByte inline read_byte(ZFile* file)
114 {
115 return fgetc(file->handle);
116 }
117
read_word(ZFile * file)118 ZUWord read_word(ZFile* file)
119 {
120 return (read_byte(file)<<8)|read_byte(file);
121 }
122
read_rword(ZFile * file)123 ZUWord read_rword(ZFile* file)
124 {
125 return read_byte(file)|(read_byte(file)<<8);
126 }
127
read_block2(ZByte * block,ZFile * file,int start_pos,int end_pos)128 void read_block2(ZByte* block, ZFile* file, int start_pos, int end_pos)
129 {
130 fseek(file->handle, start_pos, SEEK_SET);
131 fread(block, end_pos-start_pos, 1, file->handle);
132 }
133
get_file_size(char * filename)134 ZDWord get_file_size(char* filename)
135 {
136 struct stat buf;
137
138 if (stat(filename, &buf) != 0)
139 {
140 return -1;
141 }
142
143 return buf.st_size;
144 }
145
end_of_file(ZFile * file)146 int end_of_file(ZFile* file)
147 {
148 return feof(file->handle)!=0;
149 }
150
write_block(ZFile * file,ZByte * block,int length)151 void write_block(ZFile* file, ZByte* block, int length)
152 {
153 fwrite(block, 1, length, file->handle);
154 }
155
write_byte(ZFile * file,ZByte byte)156 inline void write_byte(ZFile* file, ZByte byte)
157 {
158 fputc(byte, file->handle);
159 }
160
write_word(ZFile * file,ZWord word)161 void write_word(ZFile* file, ZWord word)
162 {
163 write_byte(file, word>>8);
164 write_byte(file, word);
165 }
166
write_dword(ZFile * file,ZDWord word)167 void write_dword(ZFile* file, ZDWord word)
168 {
169 write_byte(file, word>>24);
170 write_byte(file, word>>16);
171 write_byte(file, word>>8);
172 write_byte(file, word);
173 }
174
175 #elif WINDOW_SYSTEM == 2
176
177 #include <windows.h>
178
179 struct ZFile
180 {
181 HANDLE file;
182 };
183
open_file(char * filename)184 ZFile* open_file(char* filename)
185 {
186 ZFile* f;
187
188 f = malloc(sizeof(ZFile));
189
190 f->file = CreateFile(filename,
191 GENERIC_READ,
192 FILE_SHARE_READ,
193 NULL,
194 OPEN_EXISTING,
195 FILE_ATTRIBUTE_NORMAL,
196 NULL);
197
198 if (f->file == INVALID_HANDLE_VALUE)
199 {
200 free(f);
201 return NULL;
202 }
203
204 return f;
205 }
206
open_file_write(char * filename)207 ZFile* open_file_write(char* filename)
208 {
209 ZFile* f;
210
211 f = malloc(sizeof(ZFile));
212
213 f->file = CreateFile(filename,
214 GENERIC_READ|GENERIC_WRITE,
215 FILE_SHARE_READ|FILE_SHARE_WRITE,
216 NULL,
217 CREATE_ALWAYS,
218 FILE_ATTRIBUTE_NORMAL,
219 NULL);
220
221 if (f->file == INVALID_HANDLE_VALUE)
222 {
223 free(f);
224 return NULL;
225 }
226
227 return f;
228 }
229
close_file(ZFile * file)230 void close_file(ZFile* file)
231 {
232 CloseHandle(file->file);
233 free(file);
234 }
235
read_byte(ZFile * file)236 ZByte read_byte(ZFile* file)
237 {
238 ZByte block[1];
239 DWORD nread;
240
241 if (!ReadFile(file->file, block, 1, &nread, NULL))
242 zmachine_fatal("Unable to read byte from file");
243 return block[0];
244 }
245
read_word(ZFile * file)246 ZUWord read_word(ZFile* file)
247 {
248 return (read_byte(file)<<8)|read_byte(file);
249 }
250
read_rword(ZFile * file)251 ZUWord read_rword(ZFile* file)
252 {
253 return read_byte(file)|(read_byte(file)<<8);
254 }
255
read_block(ZFile * file,int start_pos,int end_pos)256 ZByte* read_block(ZFile* file,
257 int start_pos,
258 int end_pos)
259 {
260 ZByte* block;
261 DWORD nread;
262
263 block = malloc(sizeof(ZByte)*(end_pos-start_pos));
264
265 if (SetFilePointer(file->file, start_pos, NULL, FILE_BEGIN) == -1)
266 {
267 zmachine_fatal("Unable to seek to %i", start_pos);
268 free(block);
269 return NULL;
270 }
271 if (!ReadFile(file->file, block, end_pos-start_pos, &nread, NULL))
272 {
273 zmachine_fatal("Unable to read %i bytes", end_pos-start_pos);
274 free(block);
275 return NULL;
276 }
277
278 if (nread != end_pos-start_pos)
279 {
280 zmachine_fatal("Tried to read %i bytes, but only got %i",
281 end_pos-start_pos, nread);
282 free(block);
283 return NULL;
284 }
285
286 return block;
287 }
288
read_block2(ZByte * block,ZFile * file,int start_pos,int end_pos)289 void read_block2(ZByte* block,
290 ZFile* file,
291 int start_pos,
292 int end_pos)
293 {
294 DWORD nread;
295
296 if (SetFilePointer(file->file, start_pos, NULL, FILE_BEGIN) == -1)
297 zmachine_fatal("Unable to seek");
298 if (!ReadFile(file->file, block, end_pos-start_pos, &nread, NULL))
299 zmachine_fatal("Unable to read file");
300
301 if (nread != end_pos-start_pos)
302 zmachine_fatal("Tried to read %i bytes, but only got %i",
303 end_pos-start_pos, nread);
304 }
305
write_block(ZFile * file,ZByte * block,int length)306 void write_block(ZFile* file, ZByte* block, int length)
307 {
308 DWORD nwrite;
309
310 WriteFile(file->file, block, length, &nwrite, NULL);
311 }
312
write_byte(ZFile * file,ZByte byte)313 void write_byte(ZFile* file, ZByte byte)
314 {
315 write_block(file, &byte, 1);
316 }
317
write_word(ZFile * file,ZWord word)318 void write_word(ZFile* file, ZWord word)
319 {
320 write_byte(file, word>>8);
321 write_byte(file, word);
322 }
323
write_dword(ZFile * file,ZDWord word)324 void write_dword(ZFile* file, ZDWord word)
325 {
326 write_byte(file, word>>24);
327 write_byte(file, word>>16);
328 write_byte(file, word>>8);
329 write_byte(file, word);
330 }
331
get_file_size(char * filename)332 ZDWord get_file_size(char* filename)
333 {
334 HANDLE hnd;
335 ZDWord sz;
336
337 hnd = CreateFile(filename,
338 GENERIC_READ,
339 FILE_SHARE_READ,
340 NULL,
341 OPEN_EXISTING,
342 FILE_ATTRIBUTE_NORMAL,
343 NULL);
344
345 if (hnd == INVALID_HANDLE_VALUE)
346 return -1;
347
348 sz = GetFileSize(hnd, NULL);
349
350 CloseHandle(hnd);
351
352 return sz;
353 }
354
355 /* end_of_file not implemented: implement to fix the Windows port */
356
357 #elif WINDOW_SYSTEM == 3
358
359 /* Mac OS file handling functions */
360
361 #include <Carbon/Carbon.h>
362 #include "carbondisplay.h"
363
364 /*
365 * We add a couple of functions to deal with opening files straight from
366 * FSRefs
367 */
368
369 struct ZFile
370 {
371 FSRef fileref;
372 SInt16 forkref;
373 int endOfFile;
374 };
375
file_error_text(OSStatus stat)376 static char* file_error_text(OSStatus stat)
377 {
378 switch (stat)
379 {
380 case notOpenErr:
381 return "Volume not found";
382 case dirFulErr:
383 return "Directory full";
384 case dskFulErr:
385 return "Disk full";
386 case nsvErr:
387 return "Volume not found";
388 case ioErr:
389 return "I/O error";
390 case bdNamErr:
391 return "Bad filename";
392 case fnOpnErr:
393 return "File not open";
394 case eofErr:
395 return "End of file";
396 case posErr:
397 return "Bad file position";
398 case tmfoErr:
399 return "Too many files open";
400 case fnfErr:
401 return "File not found";
402 case wPrErr:
403 case vLckdErr:
404 return "Volume locked";
405 case fLckdErr:
406 return "File locked";
407 case fBsyErr:
408 return "File busy";
409 case rfNumErr:
410 return "Invalid reference number";
411 default:
412 {
413 static char str[255];
414
415 sprintf(str, "Unknown reason code - %i", (int) stat);
416 return str;
417 }
418 }
419 }
420
open_file(char * filename)421 ZFile* open_file(char* filename)
422 {
423 FSRef ref;
424
425 FSPathMakeRef(filename, &ref, NULL);
426
427 return open_file_fsref(&ref);
428 }
429
open_file_write(char * filename)430 ZFile* open_file_write(char* filename)
431 {
432 FSRef ref;
433 FSSpec spec;
434 OSStatus erm;
435 FInfo inf;
436 int x;
437
438 char* dirname;
439 UniChar* uniname;
440 int lastslash = -1;
441 FSRef parent;
442
443 erm = FSPathMakeRef(filename, &ref, NULL);
444
445 if (erm != fnfErr)
446 {
447 erm = FSDeleteObject(&ref);
448 if (erm != noErr)
449 return NULL;
450 }
451
452 dirname = malloc(strlen(filename)+1);
453 uniname = malloc((strlen(filename)+1)*sizeof(int));
454 strcpy(dirname, filename);
455 for (x=0; filename[x] != 0; x++)
456 {
457 uniname[x] = filename[x];
458 if (filename[x] == '/')
459 lastslash = x;
460 }
461 uniname[x] = 0;
462
463 if (lastslash == -1)
464 {
465 free(dirname);
466 free(uniname);
467 return NULL;
468 }
469 dirname[lastslash] = 0;
470
471 erm = FSPathMakeRef(dirname, &parent, NULL);
472 if (erm != NULL)
473 {
474 free(dirname);
475 free(uniname);
476 return NULL;
477 }
478
479 erm = FSCreateFileUnicode(&parent, strlen(filename) - lastslash-1,
480 uniname + lastslash + 1,
481 kFSCatInfoNone, NULL, &ref, &spec);
482
483 if (erm != noErr)
484 {
485 free(dirname);
486 free(uniname);
487 return NULL;
488 }
489
490 free(dirname);
491 free(uniname);
492
493 FSpGetFInfo(&spec, &inf);
494
495 inf.fdType = 'BINA';
496 inf.fdCreator = SIGNATURE;
497
498 FSpSetFInfo(&spec, &inf);
499
500 return open_file_write_fsref(&ref);
501 }
502
open_file_fsref(FSRef * ref)503 ZFile* open_file_fsref(FSRef* ref)
504 {
505 HFSUniStr255 dfork;
506 ZFile *file;
507 SInt16 refnum;
508 OSErr erm;
509
510 FSGetDataForkName(&dfork);
511
512 erm = FSOpenFork(ref, dfork.length, dfork.unicode, fsRdPerm, &refnum);
513
514 if (erm != noErr)
515 return NULL;
516
517 file = malloc(sizeof(ZFile));
518 file->fileref = *ref;
519 file->forkref = refnum;
520 file->endOfFile = 0;
521
522 return file;
523 }
524
open_file_write_fsref(FSRef * ref)525 ZFile* open_file_write_fsref(FSRef* ref)
526 {
527 HFSUniStr255 dfork;
528 ZFile *file;
529 SInt16 refnum;
530 OSErr erm;
531
532 FSGetDataForkName(&dfork);
533
534 erm = FSOpenFork(ref, dfork.length, dfork.unicode, fsWrPerm, &refnum);
535
536 if (erm != noErr)
537 return NULL;
538
539 file = malloc(sizeof(ZFile));
540 file->fileref = *ref;
541 file->forkref = refnum;
542 file->endOfFile = 0;
543
544 return file;
545 }
546
get_file_fsref(ZFile * file)547 FSRef get_file_fsref(ZFile* file)
548 {
549 return file->fileref;
550 }
551
close_file(ZFile * file)552 void close_file(ZFile* file)
553 {
554 FSCloseFork(file->forkref);
555 free(file);
556 }
557
read_page(ZFile * file,int page_no)558 ZByte* read_page(ZFile* file, int page_no)
559 {
560 return read_block(file, 4096*page_no, 4096*page_no+4096);
561 }
562
read_block(ZFile * file,int start_pos,int end_pos)563 ZByte* read_block(ZFile* file, int start_pos, int end_pos)
564 {
565 ZByte* block;
566 OSStatus erm;
567 ByteCount rd;
568
569 block = malloc(end_pos-start_pos);
570 if (block == NULL)
571 return NULL;
572
573 erm = FSReadFork(file->forkref, fsFromStart, start_pos,
574 end_pos-start_pos, block, &rd);
575 if (erm != noErr)
576 zmachine_fatal("Error while reading from file - %s", file_error_text(erm));
577 if (erm == eofErr) endOfFile = 1;
578 if (rd != end_pos-start_pos)
579 zmachine_fatal("Tried to read %i items of 1 byte, got %i items",
580 end_pos-start_pos, rd);
581
582 return block;
583 }
584
read_byte(ZFile * file)585 ZByte inline read_byte(ZFile* file)
586 {
587 char byte;
588 OSErr res;
589
590 res = FSReadFork(file->forkref, fsAtMark, 0, 1, &byte, NULL);
591 if (res == eofErr) file->endOfFile = 1;
592 return byte;
593 }
594
read_word(ZFile * file)595 ZUWord read_word(ZFile* file)
596 {
597 return (read_byte(file)<<8)|read_byte(file);
598 }
599
read_rword(ZFile * file)600 ZUWord read_rword(ZFile* file)
601 {
602 return read_byte(file)|(read_byte(file)<<8);
603 }
604
read_block2(ZByte * block,ZFile * file,int start_pos,int end_pos)605 void read_block2(ZByte* block, ZFile* file, int start_pos, int end_pos)
606 {
607 OSErr erm;
608
609 erm = FSReadFork(file->forkref, fsFromStart, start_pos,
610 end_pos-start_pos, block, NULL);
611 if (erm == eofErr) file->endOfFile = 1;
612 }
613
get_file_size(char * filename)614 ZDWord get_file_size(char* filename)
615 {
616 FSRef ref;
617 OSStatus res;
618
619 res = FSPathMakeRef(filename, &ref, NULL);
620
621 if (res != noErr)
622 return -1;
623
624 return get_file_size_fsref(&ref);
625 }
626
end_of_file(ZFile * file)627 int end_of_file(ZFile* file)
628 {
629 return file->endOfFile;
630 }
631
get_file_size_fsref(FSRef * file)632 ZDWord get_file_size_fsref(FSRef* file)
633 {
634 FSCatalogInfo inf;
635
636 FSGetCatalogInfo(file, kFSCatInfoDataSizes, &inf, NULL, NULL, NULL);
637
638 return inf.dataLogicalSize;
639 }
640
write_block(ZFile * file,ZByte * block,int length)641 void write_block(ZFile* file, ZByte* block, int length)
642 {
643 FSWriteFork(file->forkref, fsAtMark, 0, length, block, NULL);
644 }
645
write_byte(ZFile * file,ZByte byte)646 inline void write_byte(ZFile* file, ZByte byte)
647 {
648 FSWriteFork(file->forkref, fsAtMark, 0, 1, &byte, NULL);
649 }
650
write_word(ZFile * file,ZWord word)651 void write_word(ZFile* file, ZWord word)
652 {
653 write_byte(file, word>>8);
654 write_byte(file, word);
655 }
656
write_dword(ZFile * file,ZDWord word)657 void write_dword(ZFile* file, ZDWord word)
658 {
659 write_byte(file, word>>24);
660 write_byte(file, word>>16);
661 write_byte(file, word>>8);
662 write_byte(file, word);
663 }
664
665 #endif
666
write_string(ZFile * file,const char * string)667 void write_string(ZFile* file, const char* string) {
668 write_block(file, (unsigned char*)string, strlen(string));
669 }
670
write_stringf(ZFile * file,const char * format,...)671 void write_stringf(ZFile* file, const char* format, ...) {
672 char buffer[4096];
673 va_list ap;
674
675 va_start(ap, format);
676 vsnprintf(buffer, 4096, format, ap);
677 buffer[4095] = 0;
678 va_end(ap);
679
680 write_string(file, buffer);
681 }
682
write_stringu(ZFile * file,const int * string)683 void write_stringu(ZFile* file, const int* string) {
684 /* Maybe FIXME: write in UTF-8 format? */
685 int len, x;
686 char* str;
687
688 for (len=0; string[len] != 0; len++);
689
690 str = malloc(len+1);
691
692 for (x=0; x<len; x++) {
693 str[x] = string[x]<128?string[x]:'?';
694 }
695 str[x] = 0;
696
697 write_string(file, str);
698
699 free(str);
700 }
701