HTML5FileIO


(Posted 2 months ago) RonTek

A wrapper for a rudimentary set of Blitz3D-like sequential file commands, using localStorage in HTML5 based games.

Author: Dieter

'html5fileio... for monkey html5 target only
'By Dieter Marfurt, oct. 2016

'Browser must support local webstorage.
'Very simple, unsophisticated implementation of some common file io commands
'ReadFile, WriteFile ReadLine, WriteLine, ReadBytes, WriteBytes, Eof, CloseFile,
'working on client machines over webhtml5 pages.
'
'It cannot access existing files that it has not saved by it's own, therefor you 
'need to save from other sources (eg. from strings in code) what you want to load.
'However, such local webstorage is meant to save individual user data.

'Webstorage works (at least here)  with strings containing all ascii chars 0 to 255.
'The functions ReadBytesHtml5 and WriteBytesHtml5 were added to allow for sequentally 
'r/w any byte containing string, but they are only briefly tested yet. Keep in mind that
'javascript interpretes certain control sequences in certain contexts, such as eg.
'"\n" as a linebreak when written to an alert. Furthermore, backlashes may need to be
'backlashed ("\\") to prevent accidental control code interpretation. This does however 
'only affect strings that are written to an interpreting handler such as the 
'html page or some OS output, such as alerts and prompts etc.
'Also, when using Print, some Charcters are interpreted, such as Return, Tab...
'But useing Strings as binary memory blocks seems to work fine.

'Additionally there are some functions to emulate simple basic commands, such as
'asc, mid$, chr$, some as monkey functions, some as javascript functions in monkeygame.html.

'IMPORTANT: 

'to use these functions in your project, you must also copy the added javascript 
'functions of this demo (in MonkeyGame.html) to your MonkeyGame.html, located in 
'your "build...\html5\" folder.

Import mojo

'\/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
' init globals for file io Example...
Global chr13:String
Global csp_z:Int=0
Global csp_file_stackmax:Int=1000 ' max open files simultantously
Global csp_n:Int=csp_file_stackmax
Global EofHtml5:Int[]
Global csp_file_handle:Int[]
Global csp_file_name:String[]
Global csp_file_status:Int[]
Global csp_file_pointer:Int[]
Global csp_asciihandler:Int[]
'/\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Class csp_html5fileioClass Extends App

    Method OnCreate()

'\/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
' Example:

'init arrays etc
Local i:Int=0
Local j:Int=0
For i = 0 To csp_file_stackmax-1
EofHtml5[i]=0
csp_file_handle[i]=0
csp_file_status[i]=0
csp_file_pointer[i]=0
csp_file_name[i]=""
Next

'// Note:line delimitter for ReadLineHtml5() and WriteLineHtml5() is
'// currently windows linebreak (csp_Chr(13)), so strings used may not contain such.
'// You may also use csp_Chr(0) for zero-termination Or csp_Chr(12)+csp_Chr(10) 
'// for unix-linebreak. Param of csp_Chr() must be ascii from 0 to 255.
chr13=""
chr13=csp_Chr(13) ' define linebreak we want to use (mea culpa, I'm too stupid to use monkeys builtin FromChar() function, lol, anyway...)
Local wr:Int=0
Local re:Int=0
Local dummy:Int=0
Local my_storagefile:String="test.txt"
Local retdumm:String=" "
Local retcode:Int=0
dummy=csp_WebStorageSupported()
'If csp_WebStorageSupported()=0 Then
If dummy=0 Then
 Print "error: Web Storage seems to be unsupported by your browser"
Else
 Print "Web Storage seems to be supported."
Endif
'-----------------------------------------------------------------------------------------
Print "test read write line strings..."
'test writeline, readline...

'write some lines to a file
wr=WriteFileHtml5(my_storagefile)   ' Open file (overwrite if existing). note: you can only write to a file opened for writing
For i=0 To 5
 dummy=WriteLineHtml5(wr,"hello world "+i)
Next
dummy=CloseFileHtml5(wr)
wr=0

'read them back in
re=ReadFileHtml5(my_storagefile)    ' open file for reading. note: you can only read from a file opened for reading
While EofHtml5[re]=0                ' note: this is an array, not a function
 retdumm=ReadLineHtml5(re)
 Print "|"+retdumm+ "|"
Wend
CloseFileHtml5(re)
re=0
' WARNING: writing data to a handle that was closed before, will result 
'          in access to the wrong file and/or in error(s)! It is therefor strongly
'          reccommended to set the handle variable to zero right after closing.

'-------------------------------------------------------------------------------------------
Print "test read write binary string..."
'now test binary save / load
Local binstring:String=""
For j=0 To 1
 For i=0 To 255
  binstring=binstring+csp_Chr(i)
 Next
Next'512 bytes

my_storagefile="test2.txt"

wr=WriteFileHtml5(my_storagefile)   ' Open File for writing. note: you can only write to a file opened for writing
For i=0 To 1
 dummy=WriteBytesHtml5(wr,binstring)' Sequentially write to the file
 dummy=WriteBytesHtml5(wr,binstring)
Next
dummy=CloseFileHtml5(wr)
wr=0

'read it back in

Local fl:Int=0
re=ReadFileHtml5(my_storagefile)    ' note: you can only read from a file opened for reading
While EofHtml5[re]=0                ' note: this is an array, not a function
 retdumm=ReadBytesHtml5(re,256)     ' reads sequentially 256 bytes to a string
 'print retdumm
 Print retdumm.Length

 ' just a way to check whether all bytes are still intact
  For i= 0 To retdumm.Length-1
   retcode=csp_Asc(csp_Mid(retdumm,i,1))
   If retcode<>i
    Print "error, dude!"
   Endif
  Next

 'Endif
Wend
CloseFileHtml5(re)
re=0

Print "done..."

'/\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

        SetUpdateRate 20
    End Method

    Method OnUpdate()
            UpdateAsyncEvents

    End Method

    Method OnRender()
        If csp_z<5
        Cls 0,0,0
        'Print csp_z
        csp_z+=1
        Endif
    End Method

End
'--------------------------------------------------------------------------------------

'html5fileio monkey functions:
Function ReadFileHtml5:Int(fname:String)
 If fname="" Then
  Return 0
 Endif

 '// check If file already open...
 Local i:Int=0
 For i=0 To csp_file_stackmax-1
  If(csp_file_handle[i]=1)Then
   If(csp_file_name[i]=fname)Then
   Print fname+""+csp_file_name[i]
    Return i
   Endif
  Endif
 Next
 '// find free slot For a handle
 For i=0 To csp_file_stackmax-1
  If(csp_file_handle[i]=0) Then
   csp_file_name[i]=fname
   csp_file_pointer[i]=0
   EofHtml5[i+1]=0 ' we use index+1 to allow us useing the returned filehandle as index externally, see example...
   csp_file_status[i]=1 '// 1: is open For reading, 2: is open For writing
   csp_file_handle[i]=1 '// 1: mark as busy slot
   Return i+1 ' we provide index+1 as the filehandle...
  Endif
 Next
 Return 0 ' error, something wrong
End Function

Function WriteFileHtml5:Int(fname:String)
 ' for more info see ReadFileHtml5:Int(fname:String)
 '// check If file already open...
 Local i:Int=0
 For i=0 To csp_file_stackmax-1
  If(csp_file_handle[i]=1)Then
   If(csp_file_name[i]=fname)Then
    Return i '// ignore call If so 
   Endif
  Endif
 Next

 '// find free slot For a handle
 For i=0 To csp_file_stackmax-1
  If(csp_file_handle[i]=0) Then
   csp_SetWebStorage(fname,"") ' overwrite potentially existing file
   csp_file_name[i]=fname
   csp_file_pointer[i]=0
   EofHtml5[i+1]=0
   csp_file_status[i]=2 '// 1: is open For reading, 2: is open For writing
   csp_file_handle[i]=1 '// 1: mark as busy slot
   Return i+1
  Endif
 Next
 Return 0
End Function

Function CloseFileHtml5:Int(i:Int)
 'this releases the file handle. Opened files should always be closed again.
 'warning: writing data to a handle that was closed before, will result in access to the wrong file and/or in error(s)!
 'recc.: set handle variable to zero right after closing the file using this function.
 i-=1
 If (i>=0) And (i=0) And (i0))Then
   csp_cache = csp_GetWebStorage(csp_file_name[i])
   If(csp_file_pointer[i]+1 > csp_cache.Length)Then
    EofHtml5[i+1]=1
    Return "" '// is eof!
   Endif

   wo=csp_cache.Find(chr13,csp_file_pointer[i])

   If(wo=csp_cache.Length-1)Then
    EofHtml5[i+1]=1 ' last chr13 is last byte in string, no need to go past it
   Endif
   If(wo<0)Then
    wo=csp_cache.Length '// rest of content has nomore chr13
    EofHtml5[i+1]=1 ' we'll be eof after returning this last line
   Endif
   line=csp_Mid(csp_cache,csp_file_pointer[i] ,wo-csp_file_pointer[i]) 
   csp_file_pointer[i]=wo+chr13.Length
   Return line
  Endif
 Endif
 Return ""'; // you may instead Throw an Error here. as it is, it will Return a "" String, even If the file is Not open Or does Not exist.
End Function

Function WriteLineHtml5:Int(i:Int,line:String)
 i-=1
 If(i>=0) And (i0) And (csp_file_status[i]=2)) Then
   Local csp_cache:String = csp_GetWebStorage(csp_file_name[i])
   csp_cache=csp_cache+line+chr13
   csp_SetWebStorage(csp_file_name[i],csp_cache)
   Return 1
  Endif
 Endif
 Return 0
End Function

Function ReadBytesHtml5:String(i:Int,l:Int)
 i-=1
 Local line:String=""
 Local csp_cache:String=""
 Local wo:Int=0
 If(i>=0) And (i0))Then
   csp_cache = csp_GetWebStorage(csp_file_name[i])
   If(csp_file_pointer[i]+1 > csp_cache.Length)Then
    EofHtml5[i+1]=1
    Return "" '// is eof!
   Endif

   wo=csp_file_pointer[i]+l'csp_cache.Find(chr13,csp_file_pointer[i])

   If(wo>=csp_cache.Length)Then
    wo=csp_cache.Length '// rest of content has nomore chr13
    EofHtml5[i+1]=1 ' last chr13 is last byte in string, no need to go past it
   Endif

   line=csp_Mid(csp_cache,csp_file_pointer[i] ,wo-csp_file_pointer[i]) 
   csp_file_pointer[i]=wo'+chr13.Length
   Return line
  Endif
 Endif
 Return ""'; // you may instead Throw an Error here. as it is, it will Return a "" String, even If the file is Not open Or does Not exist.
End Function

Function WriteBytesHtml5:Int(i:Int,line:String)
 i-=1
 If(i>=0) And (i0) And (csp_file_status[i]=2)) Then
   Local csp_cache:String = csp_GetWebStorage(csp_file_name[i])
   csp_cache=csp_cache+line
   csp_SetWebStorage(csp_file_name[i],csp_cache)
   Return 1
  Endif
 Endif
 Return 0
End Function

Function csp_Asc:Int(zz:String)
 csp_asciihandler=zz.ToChars()
 Return csp_asciihandler[0]
End Function

Extern
' external javascript functions in monkeygame.html:
Function csp_WebStorageSupported:Int()
Function csp_DeleteWebStorage:Int(xx:String)
Function csp_GetWebStorage:String(xx:String)
Function csp_SetWebStorage:Int(xx:String,yy:String)
Function csp_Mid:String(xx:String,yy:Int,zz:Int) ' note: index starts at zero, unlike BASIC which starts at 1.
Function csp_Chr:String(zz:Int)
Public

Function Main()
    New csp_html5fileioClass
End

Javascript Code to be added in HTML5 file (MonkeyGame.html)


// functions added by Dieter Marfurt for html5fileio example:

function csp_SetWebStorage(csplabel,cspvalue)
{
 localStorage.setItem(csplabel,cspvalue);
 return 1;
// use sessionStorage instead of localStorage if the files should be deleted when the 
// browser tab is closed. Else they're stored permanently.
}

function csp_GetWebStorage(csplabel)
{
 var cspvalue = localStorage.getItem(csplabel);
 return cspvalue;
}

function csp_DeleteWebStorage(csplabel)
{
 localStorage.removeItem(csplabel); // to completely remove a file, btw.
 return 1;
}

function csp_WebStorageSupported()
{
var a="";
a=typeof(Storage);
//alert("|"+a+"|");
if(a=="function");
{return 1;}
return 0; // I read the string would be "undefined" when NOT supported.
}

function csp_Mid(cspstring,cspstart,csplen)
{
 return cspstring.substring(cspstart,cspstart+csplen);
}

function csp_Chr(cspascii)
{
 var a=cspascii.toString(16);
 if(a.length<2)
  {a="0"+a;}
 a="%"+a;
 return unescape(a);
}
(Posted 2 months ago)

TODO: Convert this to a standard/native js module extension so there is no need to manually place the accompanying external javascript routines.

Reply To Topic

Please log in to reply