--****************************************************************************
-- Software: BINARY FILE INTERFACE (fileIO Xtra version)
-- Version: 0.4 - D10 version based on binary strings
-- Date: 2015-02-03
-- Author: Valentin Schmidt
--
-- Requirements/Dependencies:
-- - Xtra "fileIO"
--
-- Interface for binary file operations
--
-- ************************************************************************
--------------------------------------
-- Opens file with specified mode, returns file pointer (xtra instance) or false
-- @param {string} tFile
-- @param {string} tMode - r, w, a, r+, w+, a+ (,rw, wr)
-- @return {instance|false}
--------------------------------------
on fopen (tFile, tMode)
fp = xtra("fileIO").new()
-- 'r' Open for reading only; place the file pointer at the beginning of the file.
-- 'r+' Open for reading and writing; place the file pointer at the beginning of the file.
-- 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
-- 'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
-- 'a' Open for writing only; place the file pointer at the end of the file. If the file does not exist, attempt to create it.
-- 'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does not exist, attempt to create it.
case (tMode) of
"r":
fp.openFile(tFile, 1)
"r+","rw","wr":
fp.openFile(tFile, 0)
"w":
fp.createFile(tFile)
fp.openFile(tFile, 2)
"w+":
fp.createFile(tFile)
fp.openFile(tFile, 0)
"a":
fp.openFile(tFile, 2)
fp.setPosition(fp.getLength())
"a+":
fp.openFile(tFile, 0)
fp.setPosition(fp.getLength())
otherwise:
return false
end case
if (fp.status()<>0) then fp = 0
return fp
end
--------------------------------------
-- Closes open file
-- @param {instance} fp
--------------------------------------
on fclose (fp)
fp.closeFile()
fp = 0
end
--------------------------------------
-- Reads n (non-binary) bytes from open file, returns string
-- @param {instance} fp
-- @param {integer} n
-- @return {string}
--------------------------------------
on freadstring(fp, n)
if voidP(n) then n = fp.getLength() - fp.getPosition()
data = ""
repeat with i = 1 to n
c = fp.readChar()
if fp.status()<>0 then exit repeat
put c after data
end repeat
return data
end
--------------------------------------
-- Writes string to open file
-- @param {instance} fp
-- @param {string} str
--------------------------------------
on fwritestring (fp, str)
fp.writeString(str)
end
--------------------------------------
-- Reads n bytes from open file, returns (binary) string
-- @param {instance} fp
-- @param {integer} n
-- @return {string}
--------------------------------------
on freadbytes(fp, n)
if voidP(n) then n = fp.getLength() - fp.getPosition()
data = ""
repeat with i = 1 to n
c = fp.readChar()
if fp.status()<>0 then exit repeat
put numtochar(chartonum(c)) after data
end repeat
return data
end
--------------------------------------
-- Writes (binary) string to open file (alias of fwritestring)
-- @param {instance} fp
-- @param {string} str
--------------------------------------
on fwritebytes (fp, str)
fp.writeString(str)
end
--------------------------------------
-- Returns position in open file
-- @param {instance} fp
-- @return {integer}
--------------------------------------
on ftell (fp)
return fp.getPosition()
end
--------------------------------------
-- Sets position in open file
-- whence: either integer or symbol
-- 0 or #SEEK_SET: set position to offset bytes. (default)
-- 1 or #SEEK_CUR: set position to current position plus offset.
-- 2 or #SEEK_END: set position to end of file plus offset.
-- @param {instance} fp
-- @param {integer} pos
-- @param {integer|symbol} whence - optional, default = 0
-- @return {bool} success
--------------------------------------
on fseek (fp, pos, whence)
if voidP(whence) then whence = 0
else if ilk(whence)=#symbol then
whence = [#SEEK_SET, #SEEK_CUR, #SEEK_END].getPos(whence)
if whence>0 then whence=whence-1
end if
case (whence) of
0: fp.setPosition(pos)
1: fp.setPosition(fp.getPosition() + pos)
2: fp.setPosition(fp.getLength() + pos)
end case
return (fp.status()=0)
end
--------------------------------------
-- Returns size of open file
-- @param {instance} fp
-- @return {integer}
--------------------------------------
on fsize (fp)
return fp.getLength()
end
--**************************************
-- global functions, no file pointer passed
--**************************************
----------------------------------------
-- Returns file size
-- @param {string} tFile
-- @return {integer|false}
----------------------------------------
on file_size (tFile)
fp = xtra("fileIO").new()
fp.openFile(tFile, 1)
err = fp.status()
if err<>0 then return false
len = fp.getLength()
fp.closeFile()
fp = 0
return len
end
----------------------------------------
-- Truncates file
-- WARNING: only suited for smaller files, reads complete file into RAM!
-- @param {string} tFile
-- @param {integer} tSize
-- @return {bool} success
----------------------------------------
on file_truncate (tFile, tSize)
fp = xtra("fileIO").new()
fp.openFile(tFile, 0)
data = ""
repeat with i = 1 to tSize
c = fp.readChar()
if fp.status()<>0 then exit repeat
put numtochar(chartonum(c)) after data
end repeat
fn = fp.fileName()
fp.delete()
fp.createFile(fn)
fp.openFile(fn, 2)
fp.writeString(data)
err = fp.status()
fp.closeFile()
fp=0
return (err=0)
end
----------------------------------------
-- Deletes file
-- @param {string} tFile
-- @return {bool} success
----------------------------------------
on file_delete (tFile)
fp = xtra("fileIO").new()
fp.openFile(tFile, 0)
err = fp.status()
if (err=0) then err = fp.delete()
fp = 0
return (err=0)
end
----------------------------------------
-- @param {string} tFile
-- @return {bool} exists
----------------------------------------
on file_exists (tFile)
fp = xtra("fileIO").new()
fp.openFile(tFile, 1)
stat = fp.status()
fp.closeFile()
fp = 0
return (stat<>-37)
end
----------------------------------------
-- Reads whole (non-binary) file, returns string
-- @param {string} tFile
-- @return {string|false}
----------------------------------------
on file_get_string (tFile)
fp = xtra("fileIO").new()
fp.openFile(tFile,1)
err = fp.status()
if (err) then return false
ret = fp.readFile()
fp.closeFile()
fp = 0
return ret
end
----------------------------------------
-- Saves string as file
-- @param {string} tFile
-- @param {string} tString
-- @return {bool} success
----------------------------------------
on file_put_string (tFile, tString)
fp = xtra("fileIO").new()
fp.openFile(tFile, 1)
err = fp.status()
if (err=0) then fp.delete()
else if (err and not (err = -37)) then return false
fp.createFile(tFile)
err = fp.status()
if (err<>0) then return false
fp.openFile(tFile, 2)
err = fp.status()
if (err<>0) then return false
fp.writeString(tString)
fp.closeFile()
fp=0
return (err=0)
end
----------------------------------------
-- Reads whole binary file, returns binary string
-- Includes optimization for dealing with large strings
-- @param {string} tFile
-- @return {string|false}
----------------------------------------
on file_get_bytes (tFile)
fp = xtra("fileIO").new()
fp.openFile(tFile, 1)
err = fp.status()
if (err<>0) then return false
subLengthLim = 5000 -- adjust!
chunks = []
tmp = ""
repeat while true
c=fp.readChar()
if fp.status()<>0 then exit repeat
put numtochar(chartonum(c)) after tmp
if length(tmp) > subLengthLim then
chunks.append(tmp)
tmp = ""
end if
end repeat
-- assemble as large string
data = ""
repeat with str in chunks
put str after data
end repeat
put tmp after data
fp.closeFile()
fp = 0
return data
end
----------------------------------------
-- Saves (binary) string as file (alias of file_put_string)
-- @param {string} tFile
-- @param {string} tString
-- @return {bool} success
----------------------------------------
on file_put_bytes (tFile, tString)
return file_put_string(tFile, tString)
end
----------------------------------------
-- Display open file dialog
-- @param {string} title - optional, ignored in fileIO version
-- @param {string} filterMask - optional
-- @param {string} defaultFileName - optional, ignored in fileIO version
-- @return {string} filename
----------------------------------------
on display_open (title, filterMask, defaultFileName)
fio=xtra("fileIO").new()
fio.setFilterMask(filterMask)
fn=fio.displayOpen()
fio=0
return string(fn)
end
----------------------------------------
-- Display save file dialog
-- @param {string} title
-- @param {string} filterMask - optional
-- @param {string} defaultFileName
-- @return {string} filename
----------------------------------------
on display_save (title, filterMask, defaultFileName)
fio=xtra("fileIO").new()
fio.setFilterMask(filterMask)
fn=fio.displaySave(title, defaultFileName)
fio=0
return string(fn)
end