aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/tads/os_frob_tads.cpp
blob: 8c8d3f10c01810c2cb3edbb61612903f9afa09fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "glk/tads/os_frob_tads.h"
#include "common/file.h"
#include "common/memstream.h"

namespace Glk {
namespace TADS {

static osfildef *openForReading(const char *fname) {
	Common::File f;
	if (f.open(fname))
		return f.readStream(f.size());
	
	Common::InSaveFile *save = g_system->getSavefileManager()->openForLoading(fname);
	return save;
}

static osfildef *openForWriting(const char *fname) {
	return g_system->getSavefileManager()->openForSaving(fname, false);
}

int osfacc(const char *fname) {
	return Common::File::exists(fname) ? 1 : 0;
}

osfildef *osfoprt(const char *fname, os_filetype_t typ) {
	return openForReading(fname);
}

osfildef *osfoprtv(const char *fname, os_filetype_t typ) {
	return openForReading(fname);
}

osfildef *osfopwt(const char *fname, os_filetype_t typ) {
	return openForWriting(fname);
}

osfildef *osfoprwt(const char *fname, os_filetype_t typ) {
	warning("ScummVM files can't be opened for both reading and writing simultaneously");
	return openForWriting(fname);
}

osfildef *osfoprwtt(const char *fname, os_filetype_t typ) {
	warning("ScummVM files can't be opened for both reading and writing simultaneously");
	return openForWriting(fname);
}

osfildef *osfopwb(const char *fname, os_filetype_t typ) {
	return openForWriting(fname);
}

osfildef *osfoprs(const char *fname, os_filetype_t typ) {
	return openForReading(fname);
}

osfildef *osfoprb(const char *fname, os_filetype_t typ) {
	return openForReading(fname);
}

osfildef *osfoprbv(const char *fname, os_filetype_t typ) {
	return openForReading(fname);
}

osfildef *osfoprwb(const char *fname, os_filetype_t typ) {
	warning("ScummVM files can't be opened for both reading and writing simultaneously");
	return openForWriting(fname);
}

osfildef *osfoprwtb(const char *fname, os_filetype_t typ) {
	warning("ScummVM files can't be opened for both reading and writing simultaneously");
	return openForWriting(fname);
}

osfildef *osfdup(osfildef *orig, const char *mode) {
	Common::SeekableReadStream *rs = dynamic_cast<Common::SeekableReadStream *>(orig);
	int32 currPos = rs->pos();

	rs->seek(0);
	osfildef *result = rs->readStream(rs->size());
	rs->seek(currPos);

	return result;
}

void os_settype(const char *f, os_filetype_t typ) {
	// No implementation
}

char *osfgets(char *buf, size_t count, osfildef *fp) {
	Common::ReadStream *rs = dynamic_cast<Common::ReadStream *>(fp);
	char *ptr = buf;
	char c;
	while (!rs->eos() && --count > 0) {
		c = rs->readByte();
		if (c == '\n' || c == '\0')
			break;
		*ptr++ = c;
	}

	*ptr++ = '\0';
	return buf;
}

int osfputs(const char *str, osfildef *fp) {
	return dynamic_cast<Common::WriteStream *>(fp)->write(str, strlen(str)) == strlen(str) ? 0 : -1;
}

void os_fprintz(osfildef *fp, const char *str) {
	dynamic_cast<Common::WriteStream *>(fp)->write(str, strlen(str));
}

void os_fprint(osfildef *fp, const char *str, size_t len) {
	Common::String s(str, str + MIN(len, strlen(str)));
	dynamic_cast<Common::WriteStream *>(fp)->write(s.c_str(), s.size());
}

int osfwb(osfildef *fp, const void *buf, size_t bufl) {
	return dynamic_cast<Common::WriteStream *>(fp)->write(buf, bufl) == bufl ? 0 : 1;
}

int osfflush(osfildef *fp) {
	return dynamic_cast<Common::WriteStream *>(fp)->flush() ? 0 : 1;
}

int osfgetc(osfildef *fp) {
	return dynamic_cast<Common::ReadStream *>(fp)->readByte();
}

int osfrb(osfildef *fp, void *buf, size_t bufl) {
	return dynamic_cast<Common::ReadStream *>(fp)->read(buf, bufl) == bufl ? 0 : 1;
}

size_t osfrbc(osfildef *fp, void *buf, size_t bufl) {
	return dynamic_cast<Common::ReadStream *>(fp)->read(buf, bufl);
}

long osfpos(osfildef *fp) {
	return dynamic_cast<Common::SeekableReadStream *>(fp)->pos();
}

int osfseek(osfildef *fp, long pos, int mode) {
	return dynamic_cast<Common::SeekableReadStream *>(fp)->seek(pos, mode);
}

void osfcls(osfildef *fp) {
	delete fp;
}

int osfdel(const char *fname) {
	return g_system->getSavefileManager()->removeSavefile(fname) ? 0 : 1;
}

int os_rename_file(const char *oldname, const char *newname) {
	return g_system->getSavefileManager()->renameSavefile(oldname, newname);
}


bool os_locate(const char *fname, int flen, const char *arg0, char *buf, size_t bufsiz) {
	Common::String name = !flen ? Common::String(fname) : Common::String(fname, fname + flen);

	if (!Common::File::exists(fname))
		return false;

	strncpy(buf, name.c_str(), bufsiz - 1);
	buf[bufsiz - 1] = '\0';
	return true;
}

osfildef *os_create_tempfile(const char *fname, char *buf) {
	strcpy(buf, "tmpfile");
	return new Common::MemoryReadWriteStream(DisposeAfterUse::YES);
}

int osfdel_temp(const char *fname) {
	// Temporary files in ScummVM are just memory streams, so there isn't a file to delete
	return 0;
}

void os_get_tmp_path(char *buf) {
	strcpy(buf, "");
}

int os_gen_temp_filename(char *buf, size_t buflen) {
	error("TODO: If results from this are being passed to file open methods, will need to do further work");
}

/* ------------------------------------------------------------------------ */

void os_set_pwd(const char *dir) {
	// No implementation
}

void os_set_pwd_file(const char *filename) {
	// No implementation
}

bool os_mkdir(const char *dir, int create_parents) {
	// Unsupported
	return false;
}

bool os_rmdir(const char *dir) {
	// Unsupported
	return false;
}

/* ------------------------------------------------------------------------ */

void os_defext(char *fname, const char *ext) {
	if (!strchr(fname, '.'))
		strcat(fname, ext);
}

void os_addext(char *fname, const char *ext) {
	strcat(fname, ext);
}

void os_remext(char *fname) {
	char *p = strchr(fname, '.');
	if (p)
		*p = '\0';
}

bool os_file_names_equal(const char *a, const char *b) {
	return !strcmp(a, b);
}

const char *os_get_root_name(const char *buf) {
	return buf;
}

bool os_is_file_absolute(const char *fname) {
	return false;
}

void os_get_path_name(char *pathbuf, size_t pathbuflen, const char *fname) {
	strcpy(pathbuf, "");
}

void os_build_full_path(char *fullpathbuf, size_t fullpathbuflen,
	const char *path, const char *filename) {
	strcpy(fullpathbuf, filename);
}

void os_combine_paths(char *fullpathbuf, size_t pathbuflen,
	const char *path, const char *filename) {
	strcpy(fullpathbuf, filename);
}

bool os_get_abs_filename(char *result_buf, size_t result_buf_size,
	const char *filename) {
	strcpy(result_buf, filename);
	return true;
}

bool os_get_rel_path(char *result_buf, size_t result_buf_size,
	const char *basepath, const char *filename) {
	strcpy(result_buf, filename);
	return true;
}

bool os_is_file_in_dir(const char *filename, const char *path,
	bool include_subdirs, bool match_self) {
	assert(!include_subdirs && !match_self);

	return Common::File::exists(filename);
}



/* ------------------------------------------------------------------------ */
/*
*   Convert an OS filename path to URL-style format.  This isn't a true URL
*   conversion; rather, it simply expresses a filename in Unix-style
*   notation, as a series of path elements separated by '/' characters.
*   Unlike true URLs, we don't use % encoding or a scheme prefix (file://,
*   etc).
*
*   The result path never ends in a trailing '/', unless the entire result
*   path is "/".  This is for consistency; even if the source path ends with
*   a local path separator, the result doesn't.
*
*   If the local file system syntax uses '/' characters as ordinary filename
*   characters, these must be replaced with some other suitable character in
*   the result, since otherwise they'd be taken as path separators when the
*   URL is parsed.  If possible, the substitution should be reversible with
*   respect to os_cvt_dir_url(), so that the same URL read back in on this
*   same platform will produce the same original filename.  One particular
*   suggestion is that if the local system uses '/' to delimit what would be
*   a filename extension on other platforms, replace '/' with '.', since
*   this will provide reversibility as well as a good mapping if the URL is
*   read back in on another platform.
*
*   The local equivalents of "." and "..", if they exist, are converted to
*   "." and ".." in the URL notation.
*
*   Examples:
*
*.   Windows: images\rooms\startroom.jpg -> images/rooms/startroom.jpg
*.   Windows: ..\startroom.jpg -> ../startroom.jpg
*.   Mac:     :images:rooms:startroom.jpg -> images/rooms/startroom.jpg
*.   Mac:     ::startroom.jpg -> ../startroom.jpg
*.   VMS:     [.images.rooms]startroom.jpg -> images/rooms/startroom.jpg
*.   VMS:     [-.images]startroom.jpg -> ../images/startroom.jpg
*.   Unix:    images/rooms/startroom.jpg -> images/rooms/startroom.jpg
*.   Unix:    ../images/startroom.jpg -> ../images/startroom.jpg
*
*   If the local name is an absolute path in the local file system (e.g.,
*   Unix /file, Windows C:\file), translate as follows.  If the local
*   operating system uses a volume or device designator (Windows C:, VMS
*   SYS$DISK:, etc), make the first element of the path the exact local
*   syntax for the device designator: /C:/ on Windows, /SYS$DISK:/ on VMS,
*   etc.  Include the local syntax for the device prefix.  For a system like
*   Unix with a unified file system root ("/"), simply start with the root
*   directory.  Examples:
*
*.    Windows:  C:\games\deep.gam         -> /C:/games/deep.gam
*.    Windows:  C:games\deep.gam          -> /C:./games/deep.gam
*.    Windows:  \\SERVER\DISK\games\deep.gam -> /\\SERVER/DISK/games/deep.gam
*.    Mac OS 9: Hard Disk:games:deep.gam  -> /Hard Disk:/games/deep.gam
*.    VMS:      SYS$DISK:[games]deep.gam  -> /SYS$DISK:/games/deep.gam
*.    Unix:     /games/deep.gam           -> /games/deep.gam
*
*   Rationale: it's effectively impossible to create a truly portable
*   representation of an absolute path.  Operating systems are too different
*   in the way they represent root paths, and even if that were solvable, a
*   root path is essentially unusable across machines anyway because it
*   creates a dependency on the contents of a particular machine's disk.  So
*   if we're called upon to translate an absolute path, we can forget about
*   trying to be truly portable and instead focus on round-trip fidelity -
*   i.e., making sure that applying os_cvt_url_dir() to our result recovers
*   the exact original path, assuming it's done on the same operating
*   system.  The approach outlined above should achieve round-trip fidelity
*   when a local path is converted to a URL and back on the same machine,
*   since the local URL-to-path converter should recognize its own special
*   type of local absolute path prefix.  It also produces reasonable results
*   on other platforms - see the os_cvt_url_dir() comments below for
*   examples of the decoding results for absolute paths moved to new
*   platforms.  The result when a device-rooted absolute path is encoded on
*   one machine and then decoded on another will generally be a local path
*   with a root on the default device/volume and an outermost directory with
*   a name based on the original machine's device/volume name.  This
*   obviously won't reproduce the exact original path, but since that's
*   impossible anyway, this is probably as good an approximation as we can
*   create.
*
*   Character sets: the input could be in local or UTF-8 character sets.
*   The implementation shouldn't care, though - just treat bytes in the
*   range 0-127 as plain ASCII, and everything else as opaque.  I.e., do not
*   quote or otherwise modify characters outside the 0-127 range.
*/
void os_cvt_dir_url(char *result_buf, size_t result_buf_size,
	const char *src_path);

/*
*   Convert a URL-style path into a filename path expressed in the local
*   file system's syntax.  Fills in result_buf with a file path, constructed
*   using the local file system syntax, that corresponds to the path in
*   src_url expressed in URL-style syntax.  Examples:
*
*   images/rooms/startroom.jpg ->
*.   Windows   -> images\rooms\startroom.jpg
*.   Mac OS 9  -> :images:rooms:startroom.jpg
*.   VMS       -> [.images.rooms]startroom.jpg
*
*   The source format isn't a true URL; it's simply a series of path
*   elements separated by '/' characters.  Unlike true URLs, our input
*   format doesn't use % encoding and doesn't have a scheme (file://, etc).
*   (Any % in the source is treated as an ordinary character and left as-is,
*   even if it looks like a %XX sequence.  Anything that looks like a scheme
*   prefix is left as-is, with any // treated as path separators.
*
*   images/file%20name.jpg ->
*.   Windows   -> images\file%20name.jpg
*
*   file://images/file.jpg ->
*.   Windows   -> file_\\images\file.jpg
*
*   Any characters in the path that are invalid in the local file system
*   naming rules are converted to "_", unless "_" is itself invalid, in
*   which case they're converted to "X".  One exception is that if '/' is a
*   valid local filename character (rather than a path separator as it is on
*   Unix and Windows), it can be used as the replacement for the character
*   that os_cvt_dir_url uses as its replacement for '/', so that this
*   substitution is reversible when a URL is generated and then read back in
*   on this same platform.
*
*   images/file:name.jpg ->
*.   Windows   -> images\file_name.jpg
*.   Mac OS 9  -> :images:file_name.jpg
*.   Unix      -> images/file:name.jpg
*
*   The path elements "." and ".." are specifically defined as having their
*   Unix meanings: "." is an alias for the preceding path element, or the
*   working directory if it's the first element, and ".." is an alias for
*   the parent of the preceding element.  When these appear as path
*   elements, this routine translates them to the appropriate local
*   conventions.  "." may be translated simply by removing it from the path,
*   since it reiterates the previous path element.  ".." may be translated
*   by removing the previous element - HOWEVER, if ".." appears as the first
*   element, it has to be retained and translated to the equivalent local
*   notation, since it will have to be applied later, when the result_buf
*   path is actually used to open a file, at which point it will combined
*   with the working directory or another base path.
*
*.  /images/../file.jpg -> [Windows] file.jpg
*.  ../images/file.jpg ->
*.   Windows  -> ..\images\file.jpg
*.   Mac OS 9 -> ::images:file.jpg
*.   VMS      -> [-.images]file.jpg
*
*   If the URL path is absolute (starts with a '/'), the routine inspects
*   the path to see if it was created by the same OS, according to the local
*   rules for converting absolute paths in os_cvt_dir_url() (see).  If so,
*   we reverse the encoding done there.  If it doesn't appear that the name
*   was created by the same operating system - that is, if reversing the
*   encoding doesn't produce a valid local filename - then we create a local
*   absolute path as follows.  If the local system uses device/volume
*   designators, we start with the current working device/volume or some
*   other suitable default volume.  We then add the first element of the
*   path, if any, as the root directory name, applying the usual "_" or "X"
*   substitution for any characters that aren't allowed in local names.  The
*   rest of the path is handled in the usual fashion.
*
*.  /images/file.jpg ->
*.    Windows -> \images\file.jpg
*.    Unix    -> /images/file.jpg
*
*.  /c:/images/file.jpg ->
*.    Windows -> c:\images\file.jpg
*.    Unix    -> /c:/images/file.jpg
*.    VMS     -> SYS$DISK:[c__.images]file.jpg
*
*.  /Hard Disk:/images/file.jpg ->
*.    Windows -> \Hard Disk_\images\file.jpg
*.    Unix    -> SYS$DISK:[Hard_Disk_.images]file.jpg
*
*   Note how the device/volume prefix becomes the top-level directory when
*   moving a path across machines.  It's simply not possible to reconstruct
*   the exact original path in such cases, since device/volume syntax rules
*   have little in common across systems.  But this seems like a good
*   approximation in that (a) it produces a valid local path, and (b) it
*   gives the user a reasonable basis for creating a set of folders to mimic
*   the original source system, if they want to use that approach to port
*   the data rather than just changing the paths internally in the source
*   material.
*
*   Character sets: use the same rules as for os_cvt_dir_url().
*/
void os_cvt_url_dir(char *result_buf, size_t result_buf_size,
	const char *src_url);


} // End of namespace TADS
} // End of namespace Glk