1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/config-manager.h"
24 #include "ags/engine/ac/asset_helper.h"
25 #include "ags/shared/ac/audio_clip_type.h"
26 #include "ags/engine/ac/file.h"
27 #include "ags/shared/ac/common.h"
28 #include "ags/engine/ac/game.h"
29 #include "ags/engine/ac/game_setup.h"
30 #include "ags/shared/ac/game_setup_struct.h"
31 #include "ags/engine/ac/global_file.h"
32 #include "ags/engine/ac/path_helper.h"
33 #include "ags/engine/ac/runtime_defines.h"
34 #include "ags/engine/ac/string.h"
35 #include "ags/engine/debugging/debug_log.h"
36 #include "ags/engine/debugging/debugger.h"
37 #include "ags/engine/platform/base/ags_platform_driver.h"
38 #include "ags/shared/util/stream.h"
39 #include "ags/shared/core/asset_manager.h"
40 #include "ags/shared/core/asset.h"
41 #include "ags/engine/main/engine.h"
42 #include "ags/engine/main/game_file.h"
43 #include "ags/shared/util/directory.h"
44 #include "ags/shared/util/path.h"
45 #include "ags/shared/util/string.h"
46 #include "ags/shared/util/string_utils.h"
47 #include "ags/shared/debugging/out.h"
48 #include "ags/engine/script/script_api.h"
49 #include "ags/engine/script/script_runtime.h"
50 #include "ags/engine/ac/dynobj/script_string.h"
51 #include "ags/ags.h"
52 #include "ags/globals.h"
53
54 namespace AGS3 {
55
56 using namespace AGS::Shared;
57
58 // object-based File routines
59
File_Exists(const char * fnmm)60 int File_Exists(const char *fnmm) {
61
62 ResolvedPath rp;
63 if (!ResolveScriptPath(fnmm, true, rp))
64 return 0;
65
66 return (File::TestReadFile(rp.FullPath) || File::TestReadFile(rp.AltPath)) ? 1 : 0;
67 }
68
File_Delete(const char * fnmm)69 int File_Delete(const char *fnmm) {
70
71 ResolvedPath rp;
72 if (!ResolveScriptPath(fnmm, false, rp))
73 return 0;
74
75 if (File::DeleteFile(rp.FullPath))
76 return 1;
77 if (_G(errnum) == AL_ENOENT && !rp.AltPath.IsEmpty() && rp.AltPath.Compare(rp.FullPath) != 0)
78 return File::DeleteFile(rp.AltPath) ? 1 : 0;
79 return 0;
80 }
81
sc_OpenFile(const char * fnmm,int mode)82 void *sc_OpenFile(const char *fnmm, int mode) {
83 if ((mode < scFileRead) || (mode > scFileAppend))
84 quit("!OpenFile: invalid file mode");
85
86 sc_File *scf = new sc_File();
87 if (scf->OpenFile(fnmm, mode) == 0) {
88 delete scf;
89 return nullptr;
90 }
91 ccRegisterManagedObject(scf, scf);
92 return scf;
93 }
94
File_Close(sc_File * fil)95 void File_Close(sc_File *fil) {
96 fil->Close();
97 }
98
File_WriteString(sc_File * fil,const char * towrite)99 void File_WriteString(sc_File *fil, const char *towrite) {
100 FileWrite(fil->handle, towrite);
101 }
102
File_WriteInt(sc_File * fil,int towrite)103 void File_WriteInt(sc_File *fil, int towrite) {
104 FileWriteInt(fil->handle, towrite);
105 }
106
File_WriteRawChar(sc_File * fil,int towrite)107 void File_WriteRawChar(sc_File *fil, int towrite) {
108 FileWriteRawChar(fil->handle, towrite);
109 }
110
File_WriteRawLine(sc_File * fil,const char * towrite)111 void File_WriteRawLine(sc_File *fil, const char *towrite) {
112 FileWriteRawLine(fil->handle, towrite);
113 }
114
File_ReadRawLine(sc_File * fil,char * buffer)115 void File_ReadRawLine(sc_File *fil, char *buffer) {
116 Stream *in = get_valid_file_stream_from_handle(fil->handle, "File.ReadRawLine");
117 check_strlen(buffer);
118 int i = 0;
119 while (i < _G(MAXSTRLEN) - 1) {
120 buffer[i] = in->ReadInt8();
121 if (buffer[i] == '\r') {
122 // CR -- skip LF and abort
123 in->ReadInt8();
124 break;
125 }
126 if (buffer[i] == '\n') // LF only -- abort
127 break;
128 if (in->EOS()) // EOF -- abort
129 break;
130 i++;
131 }
132 buffer[i] = 0;
133 }
134
File_ReadRawLineBack(sc_File * fil)135 const char *File_ReadRawLineBack(sc_File *fil) {
136 char readbuffer[MAX_MAXSTRLEN + 1];
137 File_ReadRawLine(fil, readbuffer);
138 return CreateNewScriptString(readbuffer);
139 }
140
File_ReadString(sc_File * fil,char * toread)141 void File_ReadString(sc_File *fil, char *toread) {
142 FileRead(fil->handle, toread);
143 }
144
File_ReadStringBack(sc_File * fil)145 const char *File_ReadStringBack(sc_File *fil) {
146 Stream *in = get_valid_file_stream_from_handle(fil->handle, "File.ReadStringBack");
147 if (in->EOS()) {
148 return CreateNewScriptString("");
149 }
150
151 size_t lle = (uint32_t)in->ReadInt32();
152 if (lle == 0) {
153 debug_script_warn("File.ReadStringBack: file was not written by WriteString");
154 return CreateNewScriptString("");
155 }
156
157 char *retVal = (char *)malloc(lle);
158 in->Read(retVal, lle);
159
160 return CreateNewScriptString(retVal, false);
161 }
162
File_ReadInt(sc_File * fil)163 int File_ReadInt(sc_File *fil) {
164 return FileReadInt(fil->handle);
165 }
166
File_ReadRawChar(sc_File * fil)167 int File_ReadRawChar(sc_File *fil) {
168 return FileReadRawChar(fil->handle);
169 }
170
File_ReadRawInt(sc_File * fil)171 int File_ReadRawInt(sc_File *fil) {
172 return FileReadRawInt(fil->handle);
173 }
174
File_Seek(sc_File * fil,int offset,int origin)175 int File_Seek(sc_File *fil, int offset, int origin) {
176 Stream *in = get_valid_file_stream_from_handle(fil->handle, "File.Seek");
177 if (!in->Seek(offset, (StreamSeek)origin)) {
178 return -1;
179 }
180 return in->GetPosition();
181 }
182
File_GetEOF(sc_File * fil)183 int File_GetEOF(sc_File *fil) {
184 if (fil->handle <= 0)
185 return 1;
186 return FileIsEOF(fil->handle);
187 }
188
File_GetError(sc_File * fil)189 int File_GetError(sc_File *fil) {
190 if (fil->handle <= 0)
191 return 1;
192 return FileIsError(fil->handle);
193 }
194
File_GetPosition(sc_File * fil)195 int File_GetPosition(sc_File *fil) {
196 if (fil->handle <= 0)
197 return -1;
198 Stream *stream = get_valid_file_stream_from_handle(fil->handle, "File.Position");
199 // TODO: a problem is that AGS script does not support unsigned or long int
200 return (int)stream->GetPosition();
201 }
202
203 //=============================================================================
204
205
206 const char *GameInstallRootToken = "$INSTALLDIR$";
207 const char *UserSavedgamesRootToken = "$MYDOCS$";
208 const char *GameSavedgamesDirToken = "$SAVEGAMEDIR$";
209 const char *GameDataDirToken = "$APPDATADIR$";
210 const char *UserConfigFileToken = "$CONFIGFILE$";
211
FixupFilename(char * filename)212 void FixupFilename(char *filename) {
213 const char *illegal = _G(platform)->GetIllegalFileChars();
214 for (char *name_ptr = filename; *name_ptr; ++name_ptr) {
215 if (*name_ptr < ' ') {
216 *name_ptr = '_';
217 } else {
218 for (const char *ch_ptr = illegal; *ch_ptr; ++ch_ptr)
219 if (*name_ptr == *ch_ptr)
220 *name_ptr = '_';
221 }
222 }
223 }
224
PathFromInstallDir(const String & path)225 String PathFromInstallDir(const String &path) {
226 if (Path::IsRelativePath(path))
227 return Path::ConcatPaths(_GP(ResPaths).DataDir, path);
228 return path;
229 }
230
PreparePathForWriting(const FSLocation & fsloc,const String & filename)231 String PreparePathForWriting(const FSLocation &fsloc, const String &filename) {
232 if (Directory::CreateAllDirectories(fsloc.BaseDir, fsloc.SubDir))
233 return Path::ConcatPaths(fsloc.FullDir, filename);
234 return "";
235 }
236
GetGlobalUserConfigDir()237 FSLocation GetGlobalUserConfigDir() {
238 String dir = _G(platform)->GetUserGlobalConfigDirectory();
239 if (Path::IsRelativePath(dir)) // relative dir is resolved relative to the game data dir
240 return FSLocation(_GP(ResPaths).DataDir, dir);
241 return FSLocation(dir);
242 }
243
GetGameUserConfigDir()244 FSLocation GetGameUserConfigDir() {
245 String dir = _G(platform)->GetUserConfigDirectory();
246 if (Path::IsRelativePath(dir)) // relative dir is resolved relative to the game data dir
247 return FSLocation(_GP(ResPaths).DataDir, dir);
248 else if (_GP(usetup).local_user_conf) // directive to use game dir location
249 return FSLocation(_GP(ResPaths).DataDir);
250 // For absolute dir, we assume it's a special directory prepared for AGS engine
251 // and therefore amend it with a game own subdir
252 return FSLocation(dir, _GP(game).saveGameFolderName);
253 }
254
255 // A helper function that deduces a data directory either using default system location,
256 // or user option from config. In case of a default location a path is appended with
257 // game's "save folder" name, which is meant to separate files from different games.
MakeGameDataDir(const String & default_dir,const String & user_option)258 static FSLocation MakeGameDataDir(const String &default_dir, const String &user_option) {
259 if (user_option.IsEmpty()) {
260 String dir = default_dir;
261 if (Path::IsRelativePath(dir)) // relative dir is resolved relative to the game data dir
262 return FSLocation(_GP(ResPaths).DataDir, dir);
263 // For absolute dir, we assume it's a special directory prepared for AGS engine
264 // and therefore amend it with a game own subdir
265 return FSLocation(dir, _GP(game).saveGameFolderName);
266 }
267 // If this location is set up by user config, then use it as is (resolving relative path if necessary)
268 String dir = user_option;
269 if (Path::IsSameOrSubDir(_GP(ResPaths).DataDir, dir)) // check if it's inside game dir
270 return FSLocation(_GP(ResPaths).DataDir, Path::MakeRelativePath(_GP(ResPaths).DataDir, dir));
271 dir = Path::MakeAbsolutePath(dir);
272 return FSLocation(dir);
273 }
274
GetGameAppDataDir()275 FSLocation GetGameAppDataDir() {
276 return MakeGameDataDir(_G(platform)->GetAllUsersDataDirectory(), _GP(usetup).shared_data_dir);
277 }
278
GetGameUserDataDir()279 FSLocation GetGameUserDataDir() {
280 return MakeGameDataDir(_G(platform)->GetUserSavedgamesDirectory(), _GP(usetup).user_data_dir);
281 }
282
ResolveScriptPath(const String & orig_sc_path,bool read_only,ResolvedPath & rp)283 bool ResolveScriptPath(const String &orig_sc_path, bool read_only, ResolvedPath &rp) {
284 debugC(::AGS::kDebugFilePath, "ResolveScriptPath(%s)", orig_sc_path.GetCStr());
285 rp = ResolvedPath();
286
287 bool is_absolute = !is_relative_filename(orig_sc_path.GetCStr());
288 if (is_absolute && !read_only) {
289 debug_script_warn("Attempt to access file '%s' denied (cannot write to absolute path)", orig_sc_path.GetCStr());
290 return false;
291 }
292
293 if (is_absolute) {
294 rp = ResolvedPath(orig_sc_path);
295 return true;
296 }
297
298 String sc_path = orig_sc_path;
299 FSLocation parent_dir;
300 String child_path;
301 String alt_path;
302 if (sc_path.CompareLeft(GameInstallRootToken) == 0) {
303 if (!read_only) {
304 debug_script_warn("Attempt to access file '%s' denied (cannot write to game installation directory)",
305 sc_path.GetCStr());
306 return false;
307 }
308 parent_dir = FSLocation(_GP(ResPaths).DataDir);
309 child_path = sc_path.Mid(strlen(GameInstallRootToken));
310 } else if (sc_path.CompareLeft(GameSavedgamesDirToken) == 0) {
311 parent_dir = get_save_game_directory();
312 child_path = sc_path.Mid(strlen(GameSavedgamesDirToken));
313 #if AGS_PLATFORM_SCUMMVM
314 // Remap "agsgame.*"
315 const char *agsSavePrefix = "/agssave.";
316 if (child_path.CompareLeft(agsSavePrefix) == 0) {
317 debugC(::AGS::kDebugFilePath, "Remapping agssave.* to ScummVM savegame files");
318 String suffix = child_path.Mid(strlen(agsSavePrefix));
319 if (suffix.CompareLeft("*") == 0) {
320 Common::String file_name = ::AGS::g_vm->getSaveStateName(999);
321 Common::replace(file_name, "999", "*");
322 child_path = file_name;
323 } else {
324 int slotNum = suffix.ToInt();
325 child_path = ::AGS::g_vm->getSaveStateName(slotNum);
326 }
327 }
328 #endif
329 } else if (sc_path.CompareLeft(GameDataDirToken) == 0) {
330 parent_dir = GetGameAppDataDir();
331 child_path = sc_path.Mid(strlen(GameDataDirToken));
332 } else {
333 child_path = sc_path;
334
335 // For cases where a file is trying to write to a game path, always remap
336 // it to write to a savefile. For normal reading, we thus need to give
337 // preference to any save file with a given name before looking in the
338 // game folder. This for example fixes an issue with The Blackwell Legacy,
339 // which wants to create a new prog.bwl in the game folder
340 parent_dir = FSLocation(SAVE_FOLDER_PREFIX);
341
342 if (read_only)
343 alt_path = Path::ConcatPaths(_GP(ResPaths).DataDir, sc_path);
344 }
345
346 // Sometimes we have multiple consecutive slashes or backslashes.
347 // Remove all of them at the start of the child path.
348 while (!child_path.IsEmpty() && (child_path[0u] == '\\' || child_path[0u] == '/'))
349 child_path.ClipLeft(1);
350
351 #if AGS_PLATFORM_SCUMMVM
352 // For files on savepath, always ensure it starts with the game target prefix to avoid
353 // conflicts (as we usually have the same save dir for all games).
354 // Also flatten the path if needed as we do not support subdirectories in the save folder.
355 if (parent_dir.BaseDir == SAVE_FOLDER_PREFIX) {
356 debugC(::AGS::kDebugFilePath, "Adding ScummVM game target prefix and flatten path");
357 child_path.Replace('/', '-');
358 String gameTarget = ConfMan.getActiveDomainName();
359 if (child_path.CompareLeftNoCase(gameTarget) != 0)
360 child_path = String::FromFormat("%s-%s", gameTarget.GetCStr(), child_path.GetCStr());
361 }
362 #endif
363
364 // don't allow write operations for relative paths outside game dir
365 ResolvedPath test_rp = ResolvedPath(parent_dir, child_path, alt_path);
366 if (!read_only) {
367 if (!Path::IsSameOrSubDir(test_rp.Loc.FullDir, test_rp.FullPath)) {
368 debug_script_warn("Attempt to access file '%s' denied (outside of game directory)", sc_path.GetCStr());
369 return false;
370 }
371 }
372
373 rp = test_rp;
374 debugC(::AGS::kDebugFilePath, "Final path: %s", rp.FullPath.GetCStr());
375 if (!rp.AltPath.IsEmpty())
376 debugC(::AGS::kDebugFilePath, "Alt path: %s", rp.AltPath.GetCStr());
377 return true;
378 }
379
ResolveWritePathAndCreateDirs(const String & sc_path,ResolvedPath & rp)380 bool ResolveWritePathAndCreateDirs(const String &sc_path, ResolvedPath &rp) {
381 if (!ResolveScriptPath(sc_path, false, rp))
382 return false;
383
384 if (!rp.Loc.SubDir.IsEmpty() &&
385 !Directory::CreateAllDirectories(rp.Loc.BaseDir, rp.Loc.SubDir)) {
386 debug_script_warn("ResolveScriptPath: failed to create all subdirectories: %s", rp.FullPath.GetCStr());
387 return false;
388 }
389 return true;
390 }
391
LocateAsset(const AssetPath & path,size_t & asset_size)392 Stream *LocateAsset(const AssetPath &path, size_t &asset_size) {
393 String assetname = path.Name;
394 String filter = path.Filter;
395 soff_t asset_sz = 0;
396 Stream *asset_stream = _GP(AssetMgr)->OpenAsset(assetname, filter, &asset_sz);
397 asset_size = asset_sz;
398 return asset_stream;
399 }
400
401 //
402 // AGS custom PACKFILE callbacks, that use our own Stream object
403 //
ags_pf_fclose(void * userdata)404 static int ags_pf_fclose(void *userdata) {
405 delete(AGS_PACKFILE_OBJ *)userdata;
406 return 0;
407 }
408
ags_pf_getc(void * userdata)409 static int ags_pf_getc(void *userdata) {
410 AGS_PACKFILE_OBJ *obj = (AGS_PACKFILE_OBJ *)userdata;
411 if (obj->remains > 0) {
412 obj->remains--;
413 return obj->stream->ReadByte();
414 }
415 return -1;
416 }
417
ags_pf_ungetc(int c,void * userdata)418 static int ags_pf_ungetc(int c, void *userdata) {
419 return -1; // we do not want to support this
420 }
421
ags_pf_fread(void * p,long n,void * userdata)422 static long ags_pf_fread(void *p, long n, void *userdata) {
423 AGS_PACKFILE_OBJ *obj = (AGS_PACKFILE_OBJ *)userdata;
424 if (obj->remains > 0) {
425 size_t read = Math::Min(obj->remains, (size_t)n);
426 obj->remains -= read;
427 return obj->stream->Read(p, read);
428 }
429 return -1;
430 }
431
ags_pf_putc(int c,void * userdata)432 static int ags_pf_putc(int c, void *userdata) {
433 return -1; // don't support write
434 }
435
ags_pf_fwrite(AL_CONST void * p,long n,void * userdata)436 static long ags_pf_fwrite(AL_CONST void *p, long n, void *userdata) {
437 return -1; // don't support write
438 }
439
ags_pf_fseek(void * userdata,int offset)440 static int ags_pf_fseek(void *userdata, int offset) {
441 return -1; // don't support seek
442 }
443
ags_pf_feof(void * userdata)444 static int ags_pf_feof(void *userdata) {
445 return ((AGS_PACKFILE_OBJ *)userdata)->remains == 0;
446 }
447
ags_pf_ferror(void * userdata)448 static int ags_pf_ferror(void *userdata) {
449 return ((AGS_PACKFILE_OBJ *)userdata)->stream->HasErrors() ? 1 : 0;
450 }
451
452 // Custom PACKFILE callback table
453 static PACKFILE_VTABLE ags_packfile_vtable = {
454 ags_pf_fclose,
455 ags_pf_getc,
456 ags_pf_ungetc,
457 ags_pf_fread,
458 ags_pf_putc,
459 ags_pf_fwrite,
460 ags_pf_fseek,
461 ags_pf_feof,
462 ags_pf_ferror
463 };
464 //
465
PackfileFromAsset(const AssetPath & path,size_t & asset_size)466 PACKFILE *PackfileFromAsset(const AssetPath &path, size_t &asset_size) {
467 Stream *asset_stream = LocateAsset(path, asset_size);
468 if (asset_stream && asset_size > 0) {
469 AGS_PACKFILE_OBJ *obj = new AGS_PACKFILE_OBJ;
470 obj->stream.reset(asset_stream);
471 obj->asset_size = asset_size;
472 obj->remains = asset_size;
473 return pack_fopen_vtable(&ags_packfile_vtable, obj);
474 }
475 return nullptr;
476 }
477
DoesAssetExistInLib(const AssetPath & path)478 bool DoesAssetExistInLib(const AssetPath &path) {
479 String assetname = path.Name;
480 String filter = path.Filter;
481 return _GP(AssetMgr)->DoesAssetExist(assetname, filter);
482 }
483
find_assetlib(const String & filename)484 String find_assetlib(const String &filename) {
485 String libname = File::FindFileCI(_GP(ResPaths).DataDir, filename);
486 if (AssetManager::IsDataFile(libname))
487 return libname;
488 if (Path::ComparePaths(_GP(ResPaths).DataDir, _GP(ResPaths).DataDir2) != 0) {
489 // Hack for running in Debugger
490 libname = File::FindFileCI(_GP(ResPaths).DataDir2, filename);
491 if (AssetManager::IsDataFile(libname))
492 return libname;
493 }
494 return "";
495 }
496
get_audio_clip_assetpath(int bundling_type,const String & filename)497 AssetPath get_audio_clip_assetpath(int bundling_type, const String &filename) {
498 return AssetPath(filename, "audio");
499 }
500
get_voice_over_assetpath(const String & filename)501 AssetPath get_voice_over_assetpath(const String &filename) {
502 return AssetPath(filename, "voice");
503 }
504
505 ScriptFileHandle valid_handles[MAX_OPEN_SCRIPT_FILES + 1];
506 // [IKM] NOTE: this is not precisely the number of files opened at this moment,
507 // but rather maximal number of handles that were used simultaneously during game run
508 int num_open_script_files = 0;
check_valid_file_handle_ptr(Stream * stream_ptr,const char * operation_name)509 ScriptFileHandle *check_valid_file_handle_ptr(Stream *stream_ptr, const char *operation_name) {
510 if (stream_ptr) {
511 for (int i = 0; i < num_open_script_files; ++i) {
512 if (stream_ptr == valid_handles[i].stream) {
513 return &valid_handles[i];
514 }
515 }
516 }
517
518 String exmsg = String::FromFormat("!%s: invalid file handle; file not previously opened or has been closed", operation_name);
519 quit(exmsg);
520 return nullptr;
521 }
522
check_valid_file_handle_int32(int32_t handle,const char * operation_name)523 ScriptFileHandle *check_valid_file_handle_int32(int32_t handle, const char *operation_name) {
524 if (handle > 0) {
525 for (int i = 0; i < num_open_script_files; ++i) {
526 if (handle == valid_handles[i].handle) {
527 return &valid_handles[i];
528 }
529 }
530 }
531
532 String exmsg = String::FromFormat("!%s: invalid file handle; file not previously opened or has been closed", operation_name);
533 quit(exmsg);
534 return nullptr;
535 }
536
get_valid_file_stream_from_handle(int32_t handle,const char * operation_name)537 Stream *get_valid_file_stream_from_handle(int32_t handle, const char *operation_name) {
538 ScriptFileHandle *sc_handle = check_valid_file_handle_int32(handle, operation_name);
539 return sc_handle ? sc_handle->stream : nullptr;
540 }
541
542 //=============================================================================
543 //
544 // Script API Functions
545 //
546 //=============================================================================
547
548 // int (const char *fnmm)
Sc_File_Delete(const RuntimeScriptValue * params,int32_t param_count)549 RuntimeScriptValue Sc_File_Delete(const RuntimeScriptValue *params, int32_t param_count) {
550 API_SCALL_INT_POBJ(File_Delete, const char);
551 }
552
553 // int (const char *fnmm)
Sc_File_Exists(const RuntimeScriptValue * params,int32_t param_count)554 RuntimeScriptValue Sc_File_Exists(const RuntimeScriptValue *params, int32_t param_count) {
555 API_SCALL_INT_POBJ(File_Exists, const char);
556 }
557
558 // void *(const char *fnmm, int mode)
Sc_sc_OpenFile(const RuntimeScriptValue * params,int32_t param_count)559 RuntimeScriptValue Sc_sc_OpenFile(const RuntimeScriptValue *params, int32_t param_count) {
560 API_SCALL_OBJAUTO_POBJ_PINT(sc_File, sc_OpenFile, const char);
561 }
562
563 // void (sc_File *fil)
Sc_File_Close(void * self,const RuntimeScriptValue * params,int32_t param_count)564 RuntimeScriptValue Sc_File_Close(void *self, const RuntimeScriptValue *params, int32_t param_count) {
565 API_OBJCALL_VOID(sc_File, File_Close);
566 }
567
568 // int (sc_File *fil)
Sc_File_ReadInt(void * self,const RuntimeScriptValue * params,int32_t param_count)569 RuntimeScriptValue Sc_File_ReadInt(void *self, const RuntimeScriptValue *params, int32_t param_count) {
570 API_OBJCALL_INT(sc_File, File_ReadInt);
571 }
572
573 // int (sc_File *fil)
Sc_File_ReadRawChar(void * self,const RuntimeScriptValue * params,int32_t param_count)574 RuntimeScriptValue Sc_File_ReadRawChar(void *self, const RuntimeScriptValue *params, int32_t param_count) {
575 API_OBJCALL_INT(sc_File, File_ReadRawChar);
576 }
577
578 // int (sc_File *fil)
Sc_File_ReadRawInt(void * self,const RuntimeScriptValue * params,int32_t param_count)579 RuntimeScriptValue Sc_File_ReadRawInt(void *self, const RuntimeScriptValue *params, int32_t param_count) {
580 API_OBJCALL_INT(sc_File, File_ReadRawInt);
581 }
582
583 // void (sc_File *fil, char* buffer)
Sc_File_ReadRawLine(void * self,const RuntimeScriptValue * params,int32_t param_count)584 RuntimeScriptValue Sc_File_ReadRawLine(void *self, const RuntimeScriptValue *params, int32_t param_count) {
585 API_OBJCALL_VOID_POBJ(sc_File, File_ReadRawLine, char);
586 }
587
588 // const char* (sc_File *fil)
Sc_File_ReadRawLineBack(void * self,const RuntimeScriptValue * params,int32_t param_count)589 RuntimeScriptValue Sc_File_ReadRawLineBack(void *self, const RuntimeScriptValue *params, int32_t param_count) {
590 API_CONST_OBJCALL_OBJ(sc_File, const char, _GP(myScriptStringImpl), File_ReadRawLineBack);
591 }
592
593 // void (sc_File *fil, char *toread)
Sc_File_ReadString(void * self,const RuntimeScriptValue * params,int32_t param_count)594 RuntimeScriptValue Sc_File_ReadString(void *self, const RuntimeScriptValue *params, int32_t param_count) {
595 API_OBJCALL_VOID_POBJ(sc_File, File_ReadString, char);
596 }
597
598 // const char* (sc_File *fil)
Sc_File_ReadStringBack(void * self,const RuntimeScriptValue * params,int32_t param_count)599 RuntimeScriptValue Sc_File_ReadStringBack(void *self, const RuntimeScriptValue *params, int32_t param_count) {
600 API_CONST_OBJCALL_OBJ(sc_File, const char, _GP(myScriptStringImpl), File_ReadStringBack);
601 }
602
603 // void (sc_File *fil, int towrite)
Sc_File_WriteInt(void * self,const RuntimeScriptValue * params,int32_t param_count)604 RuntimeScriptValue Sc_File_WriteInt(void *self, const RuntimeScriptValue *params, int32_t param_count) {
605 API_OBJCALL_VOID_PINT(sc_File, File_WriteInt);
606 }
607
608 // void (sc_File *fil, int towrite)
Sc_File_WriteRawChar(void * self,const RuntimeScriptValue * params,int32_t param_count)609 RuntimeScriptValue Sc_File_WriteRawChar(void *self, const RuntimeScriptValue *params, int32_t param_count) {
610 API_OBJCALL_VOID_PINT(sc_File, File_WriteRawChar);
611 }
612
613 // void (sc_File *fil, const char *towrite)
Sc_File_WriteRawLine(void * self,const RuntimeScriptValue * params,int32_t param_count)614 RuntimeScriptValue Sc_File_WriteRawLine(void *self, const RuntimeScriptValue *params, int32_t param_count) {
615 API_OBJCALL_VOID_POBJ(sc_File, File_WriteRawLine, const char);
616 }
617
618 // void (sc_File *fil, const char *towrite)
Sc_File_WriteString(void * self,const RuntimeScriptValue * params,int32_t param_count)619 RuntimeScriptValue Sc_File_WriteString(void *self, const RuntimeScriptValue *params, int32_t param_count) {
620 API_OBJCALL_VOID_POBJ(sc_File, File_WriteString, const char);
621 }
622
Sc_File_Seek(void * self,const RuntimeScriptValue * params,int32_t param_count)623 RuntimeScriptValue Sc_File_Seek(void *self, const RuntimeScriptValue *params, int32_t param_count) {
624 API_OBJCALL_INT_PINT2(sc_File, File_Seek);
625 }
626
627 // int (sc_File *fil)
Sc_File_GetEOF(void * self,const RuntimeScriptValue * params,int32_t param_count)628 RuntimeScriptValue Sc_File_GetEOF(void *self, const RuntimeScriptValue *params, int32_t param_count) {
629 API_OBJCALL_INT(sc_File, File_GetEOF);
630 }
631
632 // int (sc_File *fil)
Sc_File_GetError(void * self,const RuntimeScriptValue * params,int32_t param_count)633 RuntimeScriptValue Sc_File_GetError(void *self, const RuntimeScriptValue *params, int32_t param_count) {
634 API_OBJCALL_INT(sc_File, File_GetError);
635 }
636
Sc_File_GetPosition(void * self,const RuntimeScriptValue * params,int32_t param_count)637 RuntimeScriptValue Sc_File_GetPosition(void *self, const RuntimeScriptValue *params, int32_t param_count) {
638 API_OBJCALL_INT(sc_File, File_GetPosition);
639 }
640
641
RegisterFileAPI()642 void RegisterFileAPI() {
643 ccAddExternalStaticFunction("File::Delete^1", Sc_File_Delete);
644 ccAddExternalStaticFunction("File::Exists^1", Sc_File_Exists);
645 ccAddExternalStaticFunction("File::Open^2", Sc_sc_OpenFile);
646 ccAddExternalObjectFunction("File::Close^0", Sc_File_Close);
647 ccAddExternalObjectFunction("File::ReadInt^0", Sc_File_ReadInt);
648 ccAddExternalObjectFunction("File::ReadRawChar^0", Sc_File_ReadRawChar);
649 ccAddExternalObjectFunction("File::ReadRawInt^0", Sc_File_ReadRawInt);
650 ccAddExternalObjectFunction("File::ReadRawLine^1", Sc_File_ReadRawLine);
651 ccAddExternalObjectFunction("File::ReadRawLineBack^0", Sc_File_ReadRawLineBack);
652 ccAddExternalObjectFunction("File::ReadString^1", Sc_File_ReadString);
653 ccAddExternalObjectFunction("File::ReadStringBack^0", Sc_File_ReadStringBack);
654 ccAddExternalObjectFunction("File::WriteInt^1", Sc_File_WriteInt);
655 ccAddExternalObjectFunction("File::WriteRawChar^1", Sc_File_WriteRawChar);
656 ccAddExternalObjectFunction("File::WriteRawLine^1", Sc_File_WriteRawLine);
657 ccAddExternalObjectFunction("File::WriteString^1", Sc_File_WriteString);
658 ccAddExternalObjectFunction("File::Seek^2", Sc_File_Seek);
659 ccAddExternalObjectFunction("File::get_EOF", Sc_File_GetEOF);
660 ccAddExternalObjectFunction("File::get_Error", Sc_File_GetError);
661 ccAddExternalObjectFunction("File::get_Position", Sc_File_GetPosition);
662 }
663
664 } // namespace AGS3
665