1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14 
15 #define USE_CLIB
16 #include "aldumb.h"
17 #include "ac/asset_helper.h"
18 #include "ac/file.h"
19 #include "ac/common.h"
20 #include "ac/gamesetup.h"
21 #include "ac/gamesetupstruct.h"
22 #include "ac/global_file.h"
23 #include "ac/path_helper.h"
24 #include "ac/runtime_defines.h"
25 #include "ac/string.h"
26 #include "debug/debug_log.h"
27 #include "debug/debugger.h"
28 #include "util/misc.h"
29 #include "platform/base/agsplatformdriver.h"
30 #include "util/stream.h"
31 #include "core/assetmanager.h"
32 #include "core/asset.h"
33 #include "main/engine.h"
34 #include "main/game_file.h"
35 #include "util/directory.h"
36 #include "util/path.h"
37 #include "util/string.h"
38 #include "util/string_utils.h"
39 
40 using namespace AGS::Common;
41 
42 extern GameSetup usetup;
43 extern GameSetupStruct game;
44 extern char saveGameDirectory[260];
45 extern AGSPlatformDriver *platform;
46 
47 extern int MAXSTRLEN;
48 
49 // TODO: the asset path configuration should certainly be revamped at some
50 // point, with uniform method of configuring auxiliary paths and packages.
51 
52 // Installation directory, may contain absolute or relative path
53 String installDirectory;
54 // Installation directory, containing audio files
55 String installAudioDirectory;
56 // Installation directory, containing voice-over files
57 String installVoiceDirectory;
58 
59 // object-based File routines
60 
File_Exists(const char * fnmm)61 int File_Exists(const char *fnmm) {
62 
63   String path, alt_path;
64   if (!ResolveScriptPath(fnmm, true, path, alt_path))
65     return 0;
66 
67   return (File::TestReadFile(path) || File::TestReadFile(alt_path)) ? 1 : 0;
68 }
69 
File_Delete(const char * fnmm)70 int File_Delete(const char *fnmm) {
71 
72   String path, alt_path;
73   if (!ResolveScriptPath(fnmm, false, path, alt_path))
74     return 0;
75 
76   if (unlink(path) == 0)
77       return 1;
78   if (errno == ENOENT && !alt_path.IsEmpty() && alt_path.Compare(path) != 0)
79       return unlink(alt_path) == 0 ? 1 : 0;
80   return 0;
81 }
82 
sc_OpenFile(const char * fnmm,int mode)83 void *sc_OpenFile(const char *fnmm, int mode) {
84   if ((mode < scFileRead) || (mode > scFileAppend))
85     quit("!OpenFile: invalid file mode");
86 
87   sc_File *scf = new sc_File();
88   if (scf->OpenFile(fnmm, mode) == 0) {
89     delete scf;
90     return 0;
91   }
92   ccRegisterManagedObject(scf, scf);
93   return scf;
94 }
95 
File_Close(sc_File * fil)96 void File_Close(sc_File *fil) {
97   fil->Close();
98 }
99 
File_WriteString(sc_File * fil,const char * towrite)100 void File_WriteString(sc_File *fil, const char *towrite) {
101   FileWrite(fil->handle, towrite);
102 }
103 
File_WriteInt(sc_File * fil,int towrite)104 void File_WriteInt(sc_File *fil, int towrite) {
105   FileWriteInt(fil->handle, towrite);
106 }
107 
File_WriteRawChar(sc_File * fil,int towrite)108 void File_WriteRawChar(sc_File *fil, int towrite) {
109   FileWriteRawChar(fil->handle, towrite);
110 }
111 
File_WriteRawLine(sc_File * fil,const char * towrite)112 void File_WriteRawLine(sc_File *fil, const char *towrite) {
113   FileWriteRawLine(fil->handle, towrite);
114 }
115 
File_ReadRawLine(sc_File * fil,char * buffer)116 void File_ReadRawLine(sc_File *fil, char* buffer) {
117   Stream *in = get_valid_file_stream_from_handle(fil->handle, "File.ReadRawLine");
118   check_strlen(buffer);
119   int i = 0;
120   while (i < MAXSTRLEN - 1) {
121     buffer[i] = in->ReadInt8();
122     if (buffer[i] == 13) {
123       // CR -- skip LF and abort
124       in->ReadInt8();
125       break;
126     }
127     if (buffer[i] == 10)  // LF only -- abort
128       break;
129     if (in->EOS())  // EOF -- abort
130       break;
131     i++;
132   }
133   buffer[i] = 0;
134 }
135 
File_ReadRawLineBack(sc_File * fil)136 const char* File_ReadRawLineBack(sc_File *fil) {
137   char readbuffer[MAX_MAXSTRLEN + 1];
138   File_ReadRawLine(fil, readbuffer);
139   return CreateNewScriptString(readbuffer);
140 }
141 
File_ReadString(sc_File * fil,char * toread)142 void File_ReadString(sc_File *fil, char *toread) {
143   FileRead(fil->handle, toread);
144 }
145 
File_ReadStringBack(sc_File * fil)146 const char* File_ReadStringBack(sc_File *fil) {
147   Stream *in = get_valid_file_stream_from_handle(fil->handle, "File.ReadStringBack");
148   if (in->EOS()) {
149     return CreateNewScriptString("");
150   }
151 
152   int lle = in->ReadInt32();
153   if ((lle >= 20000) || (lle < 1))
154     quit("!File.ReadStringBack: file was not written by WriteString");
155 
156   char *retVal = (char*)malloc(lle);
157   in->Read(retVal, lle);
158 
159   return CreateNewScriptString(retVal, false);
160 }
161 
File_ReadInt(sc_File * fil)162 int File_ReadInt(sc_File *fil) {
163   return FileReadInt(fil->handle);
164 }
165 
File_ReadRawChar(sc_File * fil)166 int File_ReadRawChar(sc_File *fil) {
167   return FileReadRawChar(fil->handle);
168 }
169 
File_ReadRawInt(sc_File * fil)170 int File_ReadRawInt(sc_File *fil) {
171   return FileReadRawInt(fil->handle);
172 }
173 
File_Seek(sc_File * fil,int offset,int origin)174 int File_Seek(sc_File *fil, int offset, int origin)
175 {
176     Stream *in = get_valid_file_stream_from_handle(fil->handle, "File.Seek");
177     return (int)in->Seek(offset, (StreamSeek)origin);
178 }
179 
File_GetEOF(sc_File * fil)180 int File_GetEOF(sc_File *fil) {
181   if (fil->handle <= 0)
182     return 1;
183   return FileIsEOF(fil->handle);
184 }
185 
File_GetError(sc_File * fil)186 int File_GetError(sc_File *fil) {
187   if (fil->handle <= 0)
188     return 1;
189   return FileIsError(fil->handle);
190 }
191 
File_GetPosition(sc_File * fil)192 int File_GetPosition(sc_File *fil)
193 {
194     if (fil->handle <= 0)
195         return -1;
196     Stream *stream = get_valid_file_stream_from_handle(fil->handle, "File.Position");
197     // TODO: a problem is that AGS script does not support unsigned or long int
198     return (int)stream->GetPosition();
199 }
200 
201 //=============================================================================
202 
203 
204 const String GameInstallRootToken    = "$INSTALLDIR$";
205 const String UserSavedgamesRootToken = "$MYDOCS$";
206 const String GameSavedgamesDirToken  = "$SAVEGAMEDIR$";
207 const String GameDataDirToken        = "$APPDATADIR$";
208 
FixupFilename(char * filename)209 void FixupFilename(char *filename)
210 {
211     const char *illegal = platform->GetIllegalFileChars();
212     for (char *name_ptr = filename; *name_ptr; ++name_ptr)
213     {
214         if (*name_ptr < ' ')
215         {
216             *name_ptr = '_';
217         }
218         else
219         {
220             for (const char *ch_ptr = illegal; *ch_ptr; ++ch_ptr)
221                 if (*name_ptr == *ch_ptr)
222                     *name_ptr = '_';
223         }
224     }
225 }
226 
227 // Tests if there is a special path token in the beginning of the given path;
228 // if there is and there is no slash between token and the rest of the string,
229 // then assigns new string that has such slash.
230 // Returns TRUE if the new string was created, and FALSE if the path was good.
FixSlashAfterToken(const String & path,const String & token,String & new_path)231 bool FixSlashAfterToken(const String &path, const String &token, String &new_path)
232 {
233     if (path.CompareLeft(token) == 0 && path.GetLength() > token.GetLength() &&
234         path[token.GetLength()] != '/')
235     {
236         new_path = String::FromFormat("%s/%s", token.GetCStr(), path.Mid(token.GetLength()).GetCStr());
237         return true;
238     }
239     return false;
240 }
241 
FixSlashAfterToken(const String & path)242 String FixSlashAfterToken(const String &path)
243 {
244     String fixed_path = path;
245     Path::FixupPath(fixed_path);
246     if (FixSlashAfterToken(fixed_path, GameInstallRootToken,    fixed_path) ||
247         FixSlashAfterToken(fixed_path, UserSavedgamesRootToken, fixed_path) ||
248         FixSlashAfterToken(fixed_path, GameSavedgamesDirToken,  fixed_path) ||
249         FixSlashAfterToken(fixed_path, GameDataDirToken,        fixed_path))
250         return fixed_path;
251     return path;
252 }
253 
MakeSpecialSubDir(const String & sp_dir)254 String MakeSpecialSubDir(const String &sp_dir)
255 {
256     if (is_relative_filename(sp_dir))
257         return sp_dir;
258     String full_path = sp_dir;
259     if (full_path.GetLast() != '/' && full_path.GetLast() != '\\')
260         full_path.AppendChar('/');
261     full_path.Append(game.saveGameFolderName);
262     Directory::CreateDirectory(full_path);
263     return full_path;
264 }
265 
MakeAppDataPath()266 String MakeAppDataPath()
267 {
268     String app_data_path = usetup.shared_data_dir;
269     if (app_data_path.IsEmpty())
270         app_data_path = MakeSpecialSubDir(PathOrCurDir(platform->GetAllUsersDataDirectory()));
271     Directory::CreateDirectory(app_data_path);
272     app_data_path.AppendChar('/');
273     return app_data_path;
274 }
275 
ResolveScriptPath(const String & orig_sc_path,bool read_only,String & path,String & alt_path)276 bool ResolveScriptPath(const String &orig_sc_path, bool read_only, String &path, String &alt_path)
277 {
278     path.Empty();
279     alt_path.Empty();
280 
281     bool is_absolute = !is_relative_filename(orig_sc_path);
282     if (is_absolute && !read_only)
283     {
284         debug_script_warn("Attempt to access file '%s' denied (cannot write to absolute path)", orig_sc_path.GetCStr());
285         return false;
286     }
287 
288     String parent_dir;
289     String child_path;
290 
291     if (is_absolute)
292     {
293         path = orig_sc_path;
294         return true;
295     }
296 
297     String sc_path = FixSlashAfterToken(orig_sc_path);
298 
299     if (sc_path.CompareLeft(GameInstallRootToken, GameInstallRootToken.GetLength()) == 0)
300     {
301         if (!read_only)
302         {
303             debug_script_warn("Attempt to access file '%s' denied (cannot write to game installation directory)",
304                 sc_path.GetCStr());
305             return false;
306         }
307         parent_dir = get_install_dir();
308         parent_dir.AppendChar('/');
309         child_path = sc_path.Mid(GameInstallRootToken.GetLength());
310     }
311     else if (sc_path.CompareLeft(GameSavedgamesDirToken, GameSavedgamesDirToken.GetLength()) == 0)
312     {
313         parent_dir = saveGameDirectory;
314         child_path = sc_path.Mid(GameSavedgamesDirToken.GetLength());
315     }
316     else if (sc_path.CompareLeft(GameDataDirToken, GameDataDirToken.GetLength()) == 0)
317     {
318         parent_dir = MakeAppDataPath();
319         child_path = sc_path.Mid(GameDataDirToken.GetLength());
320     }
321     else
322     {
323         child_path = sc_path;
324 
325         // For games which were made without having safe paths in mind,
326         // provide two paths: a path to the local directory and a path to
327         // AppData directory.
328         // This is done in case game writes a file by local path, and would
329         // like to read it back later. Since AppData path has higher priority,
330         // game will first check the AppData location and find a previously
331         // written file.
332         // If no file was written yet, but game is trying to read a pre-created
333         // file in the installation directory, then such file will be found
334         // following the 'alt_path'.
335         parent_dir = MakeAppDataPath();
336         // Set alternate non-remapped "unsafe" path for read-only operations
337         if (read_only)
338             alt_path = String::FromFormat("%s/%s", get_install_dir().GetCStr(), sc_path.GetCStr());
339 
340         // For games made in the safe-path-aware versions of AGS, report a warning
341         // if the unsafe path is used for write operation
342         if (!read_only && game.options[OPT_SAFEFILEPATHS])
343         {
344             debug_script_warn("Attempt to access file '%s' denied (cannot write to game installation directory);\nPath will be remapped to the app data directory: '%s'",
345                 sc_path.GetCStr(), parent_dir.GetCStr());
346         }
347     }
348 
349     if (child_path[0u] == '\\' || child_path[0u] == '/')
350         child_path.ClipLeft(1);
351 
352     path = String::FromFormat("%s%s", parent_dir.GetCStr(), child_path.GetCStr());
353     // don't allow write operations for relative paths outside game dir
354     if (!read_only)
355     {
356         if (!Path::IsSameOrSubDir(parent_dir, path))
357         {
358             debug_script_warn("Attempt to access file '%s' denied (outside of game directory)", sc_path.GetCStr());
359             path = "";
360             return false;
361         }
362     }
363     return true;
364 }
365 
LocateAsset(const AssetPath & path,AssetLocation & loc)366 bool LocateAsset(const AssetPath &path, AssetLocation &loc)
367 {
368     String assetlib = path.first;
369     String assetname = path.second;
370     bool needsetback = false;
371     // Change to the different library, if required
372     // TODO: teaching AssetManager to register multiple libraries simultaneously
373     // will let us skip this step, and also make this operation much faster.
374     if (!assetlib.IsEmpty() && assetlib.CompareNoCase(game_file_name) != 0)
375     {
376         AssetManager::SetDataFile(find_assetlib(assetlib));
377         needsetback = true;
378     }
379     bool res = AssetManager::GetAssetLocation(assetname, loc);
380     if (needsetback)
381         AssetManager::SetDataFile(game_file_name);
382     return res;
383 }
384 
PackfileFromAsset(const AssetPath & path)385 PACKFILE *PackfileFromAsset(const AssetPath &path)
386 {
387     AssetLocation loc;
388     if (LocateAsset(path, loc))
389     {
390         PACKFILE *pf = pack_fopen(loc.FileName, File::GetCMode(kFile_Open, kFile_Read));
391         if (pf)
392         {
393             pack_fseek(pf, loc.Offset);
394             pf->normal.todo = loc.Size;
395         }
396         return pf;
397     }
398     return NULL;
399 }
400 
DUMBfileFromAsset(const AssetPath & path)401 DUMBFILE *DUMBfileFromAsset(const AssetPath &path)
402 {
403     PACKFILE *pf = PackfileFromAsset(path);
404     if (pf)
405         return dumbfile_open_packfile(pf);
406     return NULL;
407 }
408 
DoesAssetExistInLib(const AssetPath & assetname)409 bool DoesAssetExistInLib(const AssetPath &assetname)
410 {
411     bool needsetback = false;
412     // Change to the different library, if required
413     // TODO: teaching AssetManager to register multiple libraries simultaneously
414     // will let us skip this step, and also make this operation much faster.
415     if (!assetname.first.IsEmpty() && assetname.first.CompareNoCase(game_file_name) != 0)
416     {
417         AssetManager::SetDataFile(find_assetlib(assetname.first));
418         needsetback = true;
419     }
420     bool res = AssetManager::DoesAssetExist(assetname.second);
421     if (needsetback)
422         AssetManager::SetDataFile(game_file_name);
423     return res;
424 }
425 
set_install_dir(const String & path,const String & audio_path,const String & voice_path)426 void set_install_dir(const String &path, const String &audio_path, const String &voice_path)
427 {
428     if (path.IsEmpty())
429         installDirectory = ".";
430     else
431         installDirectory = Path::MakePathNoSlash(path);
432     if (audio_path.IsEmpty())
433         installAudioDirectory = ".";
434     else
435         installAudioDirectory = Path::MakePathNoSlash(audio_path);
436     if (voice_path.IsEmpty())
437         installVoiceDirectory = ".";
438     else
439         installVoiceDirectory = Path::MakePathNoSlash(voice_path);
440 }
441 
get_install_dir()442 String get_install_dir()
443 {
444     return installDirectory;
445 }
446 
get_audio_install_dir()447 String get_audio_install_dir()
448 {
449     return installAudioDirectory;
450 }
451 
get_voice_install_dir()452 String get_voice_install_dir()
453 {
454     return installVoiceDirectory;
455 }
456 
get_install_dir_path(char * buffer,const char * fileName)457 void get_install_dir_path(char* buffer, const char *fileName)
458 {
459     sprintf(buffer, "%s/%s", installDirectory.GetCStr(), fileName);
460 }
461 
find_assetlib(const String & filename)462 String find_assetlib(const String &filename)
463 {
464     String libname = free_char_to_string( ci_find_file(usetup.data_files_dir, filename) );
465     if (AssetManager::IsDataFile(libname))
466         return libname;
467     if (Path::ComparePaths(usetup.data_files_dir, installDirectory) != 0)
468     {
469       // Hack for running in Debugger
470       libname = free_char_to_string( ci_find_file(installDirectory, filename) );
471       if (AssetManager::IsDataFile(libname))
472         return libname;
473     }
474     return "";
475 }
476 
find_open_asset(const String & filename)477 Stream *find_open_asset(const String &filename)
478 {
479     Stream *asset_s = Common::AssetManager::OpenAsset(filename);
480     if (!asset_s && Path::ComparePaths(usetup.data_files_dir, installDirectory) != 0)
481     {
482         // Just in case they're running in Debug, try standalone file in compiled folder
483         asset_s = ci_fopen(String::FromFormat("%s/%s", installDirectory.GetCStr(), filename.GetCStr()));
484     }
485     return asset_s;
486 }
487 
get_audio_clip_assetpath(int bundling_type,const String & filename)488 AssetPath get_audio_clip_assetpath(int bundling_type, const String &filename)
489 {
490     // Special case is explicitly defined audio directory, which should be
491     // tried first regardless of bundling type.
492     if (Path::ComparePaths(usetup.data_files_dir, installAudioDirectory) != 0)
493     {
494         String filepath = String::FromFormat("%s/%s", installAudioDirectory.GetCStr(), filename.GetCStr());
495         if (Path::IsFile(filepath))
496             return AssetPath("", filepath);
497     }
498 
499     if (bundling_type == AUCL_BUNDLE_EXE)
500         return AssetPath(game_file_name, filename);
501     else if (bundling_type == AUCL_BUNDLE_VOX)
502         return AssetPath(game.GetAudioVOXName(), filename);
503     return AssetPath();
504 }
505 
get_voice_over_assetpath(const String & filename)506 AssetPath get_voice_over_assetpath(const String &filename)
507 {
508     // Special case is explicitly defined voice-over directory, which should be
509     // tried first.
510     if (Path::ComparePaths(usetup.data_files_dir, installVoiceDirectory) != 0)
511     {
512         String filepath = String::FromFormat("%s/%s", installVoiceDirectory.GetCStr(), filename.GetCStr());
513         if (Path::IsFile(filepath))
514             return AssetPath("", filepath);
515     }
516     return AssetPath(speech_file, filename);
517 }
518 
519 ScriptFileHandle valid_handles[MAX_OPEN_SCRIPT_FILES + 1];
520 // [IKM] NOTE: this is not precisely the number of files opened at this moment,
521 // but rather maximal number of handles that were used simultaneously during game run
522 int num_open_script_files = 0;
check_valid_file_handle_ptr(Stream * stream_ptr,const char * operation_name)523 ScriptFileHandle *check_valid_file_handle_ptr(Stream *stream_ptr, const char *operation_name)
524 {
525   if (stream_ptr)
526   {
527       for (int i = 0; i < num_open_script_files; ++i)
528       {
529           if (stream_ptr == valid_handles[i].stream)
530           {
531               return &valid_handles[i];
532           }
533       }
534   }
535 
536   String exmsg = String::FromFormat("!%s: invalid file handle; file not previously opened or has been closed", operation_name);
537   quit(exmsg);
538   return NULL;
539 }
540 
check_valid_file_handle_int32(int32_t handle,const char * operation_name)541 ScriptFileHandle *check_valid_file_handle_int32(int32_t handle, const char *operation_name)
542 {
543   if (handle > 0)
544   {
545     for (int i = 0; i < num_open_script_files; ++i)
546     {
547         if (handle == valid_handles[i].handle)
548         {
549             return &valid_handles[i];
550         }
551     }
552   }
553 
554   String exmsg = String::FromFormat("!%s: invalid file handle; file not previously opened or has been closed", operation_name);
555   quit(exmsg);
556   return NULL;
557 }
558 
get_valid_file_stream_from_handle(int32_t handle,const char * operation_name)559 Stream *get_valid_file_stream_from_handle(int32_t handle, const char *operation_name)
560 {
561     ScriptFileHandle *sc_handle = check_valid_file_handle_int32(handle, operation_name);
562     return sc_handle ? sc_handle->stream : NULL;
563 }
564 
565 //=============================================================================
566 //
567 // Script API Functions
568 //
569 //=============================================================================
570 
571 #include "debug/out.h"
572 #include "script/script_api.h"
573 #include "script/script_runtime.h"
574 #include "ac/dynobj/scriptstring.h"
575 
576 extern ScriptString myScriptStringImpl;
577 
578 // int (const char *fnmm)
Sc_File_Delete(const RuntimeScriptValue * params,int32_t param_count)579 RuntimeScriptValue Sc_File_Delete(const RuntimeScriptValue *params, int32_t param_count)
580 {
581     API_SCALL_INT_POBJ(File_Delete, const char);
582 }
583 
584 // int (const char *fnmm)
Sc_File_Exists(const RuntimeScriptValue * params,int32_t param_count)585 RuntimeScriptValue Sc_File_Exists(const RuntimeScriptValue *params, int32_t param_count)
586 {
587     API_SCALL_INT_POBJ(File_Exists, const char);
588 }
589 
590 // void *(const char *fnmm, int mode)
Sc_sc_OpenFile(const RuntimeScriptValue * params,int32_t param_count)591 RuntimeScriptValue Sc_sc_OpenFile(const RuntimeScriptValue *params, int32_t param_count)
592 {
593     API_SCALL_OBJAUTO_POBJ_PINT(sc_File, sc_OpenFile, const char);
594 }
595 
596 // void (sc_File *fil)
Sc_File_Close(void * self,const RuntimeScriptValue * params,int32_t param_count)597 RuntimeScriptValue Sc_File_Close(void *self, const RuntimeScriptValue *params, int32_t param_count)
598 {
599     API_OBJCALL_VOID(sc_File, File_Close);
600 }
601 
602 // int (sc_File *fil)
Sc_File_ReadInt(void * self,const RuntimeScriptValue * params,int32_t param_count)603 RuntimeScriptValue Sc_File_ReadInt(void *self, const RuntimeScriptValue *params, int32_t param_count)
604 {
605     API_OBJCALL_INT(sc_File, File_ReadInt);
606 }
607 
608 // int (sc_File *fil)
Sc_File_ReadRawChar(void * self,const RuntimeScriptValue * params,int32_t param_count)609 RuntimeScriptValue Sc_File_ReadRawChar(void *self, const RuntimeScriptValue *params, int32_t param_count)
610 {
611     API_OBJCALL_INT(sc_File, File_ReadRawChar);
612 }
613 
614 // int (sc_File *fil)
Sc_File_ReadRawInt(void * self,const RuntimeScriptValue * params,int32_t param_count)615 RuntimeScriptValue Sc_File_ReadRawInt(void *self, const RuntimeScriptValue *params, int32_t param_count)
616 {
617     API_OBJCALL_INT(sc_File, File_ReadRawInt);
618 }
619 
620 // void (sc_File *fil, char* buffer)
Sc_File_ReadRawLine(void * self,const RuntimeScriptValue * params,int32_t param_count)621 RuntimeScriptValue Sc_File_ReadRawLine(void *self, const RuntimeScriptValue *params, int32_t param_count)
622 {
623     API_OBJCALL_VOID_POBJ(sc_File, File_ReadRawLine, char);
624 }
625 
626 // const char* (sc_File *fil)
Sc_File_ReadRawLineBack(void * self,const RuntimeScriptValue * params,int32_t param_count)627 RuntimeScriptValue Sc_File_ReadRawLineBack(void *self, const RuntimeScriptValue *params, int32_t param_count)
628 {
629     API_OBJCALL_OBJ(sc_File, const char, myScriptStringImpl, File_ReadRawLineBack);
630 }
631 
632 // void (sc_File *fil, char *toread)
Sc_File_ReadString(void * self,const RuntimeScriptValue * params,int32_t param_count)633 RuntimeScriptValue Sc_File_ReadString(void *self, const RuntimeScriptValue *params, int32_t param_count)
634 {
635     API_OBJCALL_VOID_POBJ(sc_File, File_ReadString, char);
636 }
637 
638 // const char* (sc_File *fil)
Sc_File_ReadStringBack(void * self,const RuntimeScriptValue * params,int32_t param_count)639 RuntimeScriptValue Sc_File_ReadStringBack(void *self, const RuntimeScriptValue *params, int32_t param_count)
640 {
641     API_OBJCALL_OBJ(sc_File, const char, myScriptStringImpl, File_ReadStringBack);
642 }
643 
644 // void (sc_File *fil, int towrite)
Sc_File_WriteInt(void * self,const RuntimeScriptValue * params,int32_t param_count)645 RuntimeScriptValue Sc_File_WriteInt(void *self, const RuntimeScriptValue *params, int32_t param_count)
646 {
647     API_OBJCALL_VOID_PINT(sc_File, File_WriteInt);
648 }
649 
650 // void (sc_File *fil, int towrite)
Sc_File_WriteRawChar(void * self,const RuntimeScriptValue * params,int32_t param_count)651 RuntimeScriptValue Sc_File_WriteRawChar(void *self, const RuntimeScriptValue *params, int32_t param_count)
652 {
653     API_OBJCALL_VOID_PINT(sc_File, File_WriteRawChar);
654 }
655 
656 // void (sc_File *fil, const char *towrite)
Sc_File_WriteRawLine(void * self,const RuntimeScriptValue * params,int32_t param_count)657 RuntimeScriptValue Sc_File_WriteRawLine(void *self, const RuntimeScriptValue *params, int32_t param_count)
658 {
659     API_OBJCALL_VOID_POBJ(sc_File, File_WriteRawLine, const char);
660 }
661 
662 // void (sc_File *fil, const char *towrite)
Sc_File_WriteString(void * self,const RuntimeScriptValue * params,int32_t param_count)663 RuntimeScriptValue Sc_File_WriteString(void *self, const RuntimeScriptValue *params, int32_t param_count)
664 {
665     API_OBJCALL_VOID_POBJ(sc_File, File_WriteString, const char);
666 }
667 
Sc_File_Seek(void * self,const RuntimeScriptValue * params,int32_t param_count)668 RuntimeScriptValue Sc_File_Seek(void *self, const RuntimeScriptValue *params, int32_t param_count)
669 {
670     API_OBJCALL_INT_PINT2(sc_File, File_Seek);
671 }
672 
673 // int (sc_File *fil)
Sc_File_GetEOF(void * self,const RuntimeScriptValue * params,int32_t param_count)674 RuntimeScriptValue Sc_File_GetEOF(void *self, const RuntimeScriptValue *params, int32_t param_count)
675 {
676     API_OBJCALL_INT(sc_File, File_GetEOF);
677 }
678 
679 // int (sc_File *fil)
Sc_File_GetError(void * self,const RuntimeScriptValue * params,int32_t param_count)680 RuntimeScriptValue Sc_File_GetError(void *self, const RuntimeScriptValue *params, int32_t param_count)
681 {
682     API_OBJCALL_INT(sc_File, File_GetError);
683 }
684 
Sc_File_GetPosition(void * self,const RuntimeScriptValue * params,int32_t param_count)685 RuntimeScriptValue Sc_File_GetPosition(void *self, const RuntimeScriptValue *params, int32_t param_count)
686 {
687     API_OBJCALL_INT(sc_File, File_GetPosition);
688 }
689 
690 
RegisterFileAPI()691 void RegisterFileAPI()
692 {
693     ccAddExternalStaticFunction("File::Delete^1",           Sc_File_Delete);
694     ccAddExternalStaticFunction("File::Exists^1",           Sc_File_Exists);
695     ccAddExternalStaticFunction("File::Open^2",             Sc_sc_OpenFile);
696     ccAddExternalObjectFunction("File::Close^0",            Sc_File_Close);
697     ccAddExternalObjectFunction("File::ReadInt^0",          Sc_File_ReadInt);
698     ccAddExternalObjectFunction("File::ReadRawChar^0",      Sc_File_ReadRawChar);
699     ccAddExternalObjectFunction("File::ReadRawInt^0",       Sc_File_ReadRawInt);
700     ccAddExternalObjectFunction("File::ReadRawLine^1",      Sc_File_ReadRawLine);
701     ccAddExternalObjectFunction("File::ReadRawLineBack^0",  Sc_File_ReadRawLineBack);
702     ccAddExternalObjectFunction("File::ReadString^1",       Sc_File_ReadString);
703     ccAddExternalObjectFunction("File::ReadStringBack^0",   Sc_File_ReadStringBack);
704     ccAddExternalObjectFunction("File::WriteInt^1",         Sc_File_WriteInt);
705     ccAddExternalObjectFunction("File::WriteRawChar^1",     Sc_File_WriteRawChar);
706     ccAddExternalObjectFunction("File::WriteRawLine^1",     Sc_File_WriteRawLine);
707     ccAddExternalObjectFunction("File::WriteString^1",      Sc_File_WriteString);
708     ccAddExternalObjectFunction("File::Seek^2",             Sc_File_Seek);
709     ccAddExternalObjectFunction("File::get_EOF",            Sc_File_GetEOF);
710     ccAddExternalObjectFunction("File::get_Error",          Sc_File_GetError);
711     ccAddExternalObjectFunction("File::get_Position",       Sc_File_GetPosition);
712 
713     /* ----------------------- Registering unsafe exports for plugins -----------------------*/
714 
715     ccAddExternalFunctionForPlugin("File::Delete^1",           (void*)File_Delete);
716     ccAddExternalFunctionForPlugin("File::Exists^1",           (void*)File_Exists);
717     ccAddExternalFunctionForPlugin("File::Open^2",             (void*)sc_OpenFile);
718     ccAddExternalFunctionForPlugin("File::Close^0",            (void*)File_Close);
719     ccAddExternalFunctionForPlugin("File::ReadInt^0",          (void*)File_ReadInt);
720     ccAddExternalFunctionForPlugin("File::ReadRawChar^0",      (void*)File_ReadRawChar);
721     ccAddExternalFunctionForPlugin("File::ReadRawInt^0",       (void*)File_ReadRawInt);
722     ccAddExternalFunctionForPlugin("File::ReadRawLine^1",      (void*)File_ReadRawLine);
723     ccAddExternalFunctionForPlugin("File::ReadRawLineBack^0",  (void*)File_ReadRawLineBack);
724     ccAddExternalFunctionForPlugin("File::ReadString^1",       (void*)File_ReadString);
725     ccAddExternalFunctionForPlugin("File::ReadStringBack^0",   (void*)File_ReadStringBack);
726     ccAddExternalFunctionForPlugin("File::WriteInt^1",         (void*)File_WriteInt);
727     ccAddExternalFunctionForPlugin("File::WriteRawChar^1",     (void*)File_WriteRawChar);
728     ccAddExternalFunctionForPlugin("File::WriteRawLine^1",     (void*)File_WriteRawLine);
729     ccAddExternalFunctionForPlugin("File::WriteString^1",      (void*)File_WriteString);
730     ccAddExternalFunctionForPlugin("File::get_EOF",            (void*)File_GetEOF);
731     ccAddExternalFunctionForPlugin("File::get_Error",          (void*)File_GetError);
732 }
733