740 lines
16 KiB
Lua
740 lines
16 KiB
Lua
bin={}
|
|
bin.Version={5,1,0}
|
|
bin.stage='stable'
|
|
bin.data=''
|
|
bin.t='bin'
|
|
bin.__index = bin
|
|
bin.__tostring=function(self) return self:getData() end
|
|
bin.__len=function(self) return self:getlength() end
|
|
bin.lastBlockSize=0
|
|
bin.streams={}
|
|
-- Helpers
|
|
function bin.getVersion()
|
|
return bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3]
|
|
end
|
|
require("bin.support.utils")
|
|
if jit then
|
|
bit=require("bit")
|
|
elseif bit32 then
|
|
bit=bit32
|
|
else
|
|
bit=require("bin.numbers.no_jit_bit")
|
|
end
|
|
base64=require("bin.converters.base64")
|
|
base91=require("bin.converters.base91")
|
|
bin.lzw=require("bin.compressors.lzw") -- A WIP
|
|
bits=require("bin.numbers.bits")
|
|
infinabits=require("bin.numbers.infinabits") -- like the bits library but works past 32 bits for 32bit lua and 64 bits for 64 bit lua.
|
|
bin.md5=require("bin.hashes.md5")
|
|
randomGen=require("bin.numbers.random")
|
|
function bin.setBitsInterface(int)
|
|
bin.defualtBit=int or bits
|
|
end
|
|
bin.setBitsInterface()
|
|
function bin.normalizeData(data) -- unified function to allow for all types to string
|
|
if type(data)=="string" then return data end
|
|
if type(data)=="table" then
|
|
if data.Type=="bin" or data.Type=="streamable" or data.Type=="buffer" then
|
|
return data:getData()
|
|
elseif data.Type=="bits" or data.Type=="infinabits" then
|
|
return data:toSbytes()
|
|
elseif data.Type=="sink" then
|
|
-- LATER
|
|
else
|
|
return ""
|
|
end
|
|
elseif type(data)=="userdata" then
|
|
if tostring(data):sub(1,4)=="file" then
|
|
local cur=data:seek("cur")
|
|
data:seek("set",0)
|
|
local dat=data:read("*a")
|
|
data:seek("set",cur)
|
|
return dat
|
|
else
|
|
error("File handles are the only userdata that can be used!")
|
|
end
|
|
end
|
|
end
|
|
function bin.resolveType(tab) -- used in getblock for auto object creation. Internal method
|
|
if tab.Type then
|
|
if tab.Type=="bin" then
|
|
return bin.new(tab.data)
|
|
elseif tab.Type=="streamable" then
|
|
if bin.fileExist(tab.file) then return nil,"Cannot load the stream file, source file does not exist!" end
|
|
return bin.stream(tab.file,tab.lock)
|
|
elseif tab.Type=="buffer" then
|
|
local buf=bin.newDataBuffer(tab.size)
|
|
buf[1]=tab:getData()
|
|
return buf
|
|
elseif tab.Type=="bits" then
|
|
local b=bits.new("")
|
|
b.data=tab.data
|
|
return b
|
|
elseif tab.Type=="infinabits" then
|
|
local b=infinabits.new("")
|
|
b.data=tab.data
|
|
return b
|
|
elseif tab.Type=="sink" then
|
|
return bin.newSync(tab.data)
|
|
else -- maybe a type from another library
|
|
return tab
|
|
end
|
|
else return tab end
|
|
end
|
|
function bin.fileExist(path)
|
|
g=io.open(path or '','r')
|
|
if path =='' then
|
|
p='empty path'
|
|
return nil
|
|
end
|
|
if g~=nil and true or false then
|
|
p=(g~=nil and true or false)
|
|
end
|
|
if g~=nil then
|
|
io.close(g)
|
|
else
|
|
return false
|
|
end
|
|
return p
|
|
end
|
|
function bin.toHex(str)
|
|
local str=bin.normalizeData(str)
|
|
return (str:gsub('.', function (c)
|
|
return string.format('%02X', string.byte(c))
|
|
end))
|
|
end
|
|
function bin.fromHex(str)
|
|
return (str:gsub('..', function (cc)
|
|
return string.char(tonumber(cc, 16))
|
|
end))
|
|
end
|
|
function bin.toBase64(s)
|
|
return base64.encode(s)
|
|
end
|
|
function bin.fromBase64(s)
|
|
return base64.decode(s)
|
|
end
|
|
function bin.toBase91(s)
|
|
return base91.encode(s)
|
|
end
|
|
function bin.fromBase91(s)
|
|
return base91.decode(s)
|
|
end
|
|
-- Constructors
|
|
function bin.new(data)
|
|
data=bin.normalizeData(data)
|
|
local c = {}
|
|
setmetatable(c, bin)
|
|
c.data=data
|
|
c.Type="bin"
|
|
c.t="bin"
|
|
c.pos=1
|
|
c.stream=false
|
|
return c
|
|
end
|
|
function bin.newFromBase64(data)
|
|
return bin.new(bin.fromBase64(data))
|
|
end
|
|
function bin.newFromBase91(data)
|
|
return bin.new(bin.fromBase91(data))
|
|
end
|
|
function bin.newFromHex(data)
|
|
return bin.new(bin.fromHex(data))
|
|
end
|
|
function bin.load(path)
|
|
if type(path) ~= "string" then error("Path must be a string!") end
|
|
local f = io.open(path, 'rb')
|
|
local content = f:read('*a')
|
|
f:close()
|
|
return bin.new(content)
|
|
end
|
|
function bin.stream(file,l)
|
|
if not(l==false) then l=true end
|
|
local c=bin.new()
|
|
c.Type="streamable"
|
|
c.t="streamable"
|
|
if bin.streams[file]~=nil then
|
|
c.file=file
|
|
c.lock = l
|
|
c.workingfile=bin.streams[file][1].workingfile
|
|
bin.streams[file][2]=bin.streams[file][2]+1
|
|
c.stream=true
|
|
return c
|
|
end
|
|
if bin.fileExist(file) then
|
|
c.file=file
|
|
c.lock = l
|
|
c.workingfile=io.open(file,'rb+')
|
|
else
|
|
c.file=file
|
|
c.lock = l
|
|
c.workingfile=io.open(file,'w')
|
|
io.close(c.workingfile)
|
|
c.workingfile=io.open(file,'rb+')
|
|
end
|
|
c.stream=true
|
|
bin.streams[file]={c,1}
|
|
return c
|
|
end
|
|
function bin.newTempFile()
|
|
local c=bin.new()
|
|
c.file=file
|
|
c.lock = false
|
|
c.workingfile=io.tmpfile()
|
|
c.stream=true
|
|
return c
|
|
end
|
|
function bin.freshStream(file)
|
|
bin.new():tofile(file)
|
|
return bin.stream(file,false)
|
|
end
|
|
function bin.newStreamFileObject(file)
|
|
local c=bin.new()
|
|
c.Type="streamable"
|
|
c.t="streamable"
|
|
c.file="FILE_OBJECT"
|
|
c.lock = false
|
|
c.workingfile=file
|
|
c.stream=true
|
|
return c
|
|
end
|
|
-- Core Methods
|
|
function bin:canStreamWrite()
|
|
return (self.stream and not(self.lock))
|
|
end
|
|
function bin:getSeek()
|
|
if self.stream then
|
|
return self.workingfile:seek("cur")+1
|
|
else
|
|
return self.pos
|
|
end
|
|
end
|
|
function bin:setSeek(n)
|
|
if self.stream then
|
|
self.workingfile:seek("set",n-1)
|
|
else
|
|
self.pos=n
|
|
end
|
|
end
|
|
function bin:seek(n)
|
|
if self.stream then
|
|
if not n then return self.workingfile:seek("cur") end
|
|
local cur=self.workingfile:seek("cur")
|
|
self.workingfile:seek("set",cur+n)
|
|
else
|
|
if not n then return self.pos end
|
|
if #self.data-(self.pos-1)<n then
|
|
print(n-((#self.data)-(self.pos-1)))
|
|
self:write(string.rep("\0",n-((#self.data)-(self.pos-1))))
|
|
return
|
|
end
|
|
self.pos=self.pos+n
|
|
end
|
|
end
|
|
function bin:read(n)
|
|
if self.stream then
|
|
return self.workingfile:read(n)
|
|
else
|
|
local data=self.data:sub(self.pos,self.pos+n-1)
|
|
self.pos=self.pos+n
|
|
if data=="" then return end
|
|
return data
|
|
end
|
|
end
|
|
function bin:write(data,size)
|
|
local data=bin.normalizeData(data)
|
|
local dsize=#data
|
|
local size=tonumber(size or dsize)
|
|
if dsize>size then
|
|
data = data:sub(1,size)
|
|
elseif dsize<size then
|
|
data=data..string.rep("\0",size-dsize)
|
|
end
|
|
if self:canStreamWrite() then
|
|
self.workingfile:write(data)
|
|
elseif self.Type=="bin" then
|
|
local tab={}
|
|
if self.pos==1 then
|
|
tab={data,self.data:sub(self.pos+size)}
|
|
else
|
|
tab={self.data:sub(1,self.pos-1),data,self.data:sub(self.pos+size)}
|
|
end
|
|
self.pos=self.pos+size
|
|
self.data=table.concat(tab)
|
|
else
|
|
error("Attempted to write to a locked file!")
|
|
end
|
|
end
|
|
function bin:sub(a,b)
|
|
local data=""
|
|
if self.stream then
|
|
local cur=self.workingfile:seek("cur")
|
|
self.workingfile:seek("set",a-1)
|
|
data=self.workingfile:read(b-(a-1))
|
|
self.workingfile:seek("set",cur)
|
|
else
|
|
data=self.data:sub(a,b)
|
|
end
|
|
return data
|
|
end
|
|
function bin:slide(n)
|
|
local s=self:getSize()
|
|
local buf=bin.newDataBuffer(s)
|
|
buf:fillBuffer(1,self:getData())
|
|
for i=1,s do
|
|
nn=buf[i]+n
|
|
if nn>255 then
|
|
nn=nn%256
|
|
elseif nn<0 then
|
|
nn=256-math.abs(nn)
|
|
end
|
|
buf[i]=nn
|
|
end
|
|
self:setSeek(1)
|
|
self:write(buf:getData())
|
|
end
|
|
function bin:getData(a,b,fmt)
|
|
local data=""
|
|
if a or b then
|
|
data=self:sub(a,b)
|
|
else
|
|
if self.stream then
|
|
local cur=self.workingfile:seek("cur")
|
|
self.workingfile:seek("set",0)
|
|
data=self.workingfile:read("*a")
|
|
self.workingfile:seek("set",cur)
|
|
else
|
|
data=self.data
|
|
end
|
|
end
|
|
if fmt=="%x" or fmt=="hex" then
|
|
return bin.toHex(data):lower()
|
|
elseif fmt=="%X" or fmt=="HEX" then
|
|
return bin.toHex(data)
|
|
elseif fmt=="%b" or fmt=="b64" then
|
|
return bin.toB64(data)
|
|
elseif fmt then
|
|
return bin.new(data):getBlock(fmt,#data)
|
|
end
|
|
return data
|
|
end
|
|
function bin:getSize(fmt)
|
|
local len=0
|
|
if self.stream then
|
|
local cur=self.workingfile:seek("cur")
|
|
len=self.workingfile:seek("end")
|
|
self.workingfile:seek("set",cur)
|
|
else
|
|
len=#self.data
|
|
end
|
|
if fmt=="%b" then
|
|
return bin.toB64()
|
|
elseif fmt then
|
|
return string.format(fmt, len)
|
|
else
|
|
return len
|
|
end
|
|
end
|
|
function bin:tackE(data,size,h)
|
|
local data=bin.normalizeData(data)
|
|
local cur=self:getSize()
|
|
self:setSeek(self:getSize()+1)
|
|
self:write(data,size)
|
|
if h then
|
|
self:setSeek(cur+1)
|
|
end
|
|
end
|
|
function bin:tonumber(a,b)
|
|
local temp={}
|
|
if a then
|
|
temp.data=self:sub(a,b)
|
|
else
|
|
temp=self
|
|
end
|
|
local l,r=0,0
|
|
local g=#temp.data
|
|
for i=1,g do
|
|
r=r+(256^(g-i))*string.byte(string.sub(temp.data,i,i))
|
|
l=l+(256^(i-1))*string.byte(string.sub(temp.data,i,i))
|
|
end
|
|
return r,l
|
|
end
|
|
function bin.endianflop(data)
|
|
return string.reverse(data)
|
|
end
|
|
function bin:tofile(name)
|
|
if self.stream then return end
|
|
if not name then error("Must include a filename to save as!") end
|
|
file = io.open(name, "wb")
|
|
file:write(self.data)
|
|
file:close()
|
|
end
|
|
function bin:close()
|
|
if self.stream then
|
|
if bin.streams[self.file][2]==1 then
|
|
bin.streams[self.file]=nil
|
|
self.workingfile:close()
|
|
else
|
|
bin.streams[self.file][2]=bin.streams[self.file][2]-1
|
|
self.workingfile=io.tmpfile()
|
|
self.workingfile:close()
|
|
end
|
|
end
|
|
end
|
|
function bin:getBlock(t,n)
|
|
local data=""
|
|
if not n then
|
|
if bin.registerBlocks[t] then
|
|
return bin.registerBlocks[t][1](nil,self)
|
|
else
|
|
error("Unknown format! Cannot read from file: "..tostring(t))
|
|
end
|
|
else
|
|
if t=="n" or t=="%e" or t=="%E" then
|
|
data=self:read(n)
|
|
local numB=bin.defualtBit.new(data)
|
|
local numL=bin.defualtBit.new(string.reverse(data))
|
|
local little=numL:tonumber(0)
|
|
local big=numB:tonumber(0)
|
|
if t=="%E" then
|
|
return big
|
|
elseif t=="%X" then
|
|
return bin.toHex(data):upper()
|
|
elseif t=="%x" then
|
|
return bin.toHex(data):lower()
|
|
elseif t=="%b" then
|
|
return bin.toB64(data)
|
|
elseif t=="%e" then
|
|
return little
|
|
end
|
|
return big,little
|
|
elseif t=="s" then
|
|
return self:read(n)
|
|
elseif bin.registerBlocks[t] then
|
|
return bin.registerBlocks[t][1](n,self)
|
|
else
|
|
error("Unknown format! Cannot read from file: "..tostring(t))
|
|
end
|
|
end
|
|
end
|
|
function bin:addBlock(d,fit,fmt)
|
|
if not fmt then fmt=type(d):sub(1,1) end
|
|
if bin.registerBlocks[fmt] then
|
|
self:tackE(bin.registerBlocks[fmt][2](d,fit,fmt,self,bin.registerBlocks[fmt][2]))
|
|
elseif type(d)=="number" then
|
|
local data=bin.defualtBit.numToBytes(d,fit or 4,fmt,function()
|
|
error("Overflow! Space allotted for number is smaller than the number takes up. Increase the fit!")
|
|
end)
|
|
self:tackE(data)
|
|
elseif type(d)=="string" then
|
|
local data=d:sub(1,fit or -1)
|
|
if #data<(fit or #data) then
|
|
data=data..string.rep("\0",fit-#data)
|
|
end
|
|
self:tackE(data)
|
|
end
|
|
end
|
|
bin.registerBlocks={}
|
|
function bin.registerBlock(t,funcG,funcA)
|
|
bin.registerBlocks[t]={funcG,funcA}
|
|
end
|
|
function bin.newDataBuffer(size,fill) -- fills with \0 or nul or with what you enter
|
|
local c={}
|
|
local fill=fill or "\0"
|
|
c.data={self=c}
|
|
c.Type="buffer"
|
|
c.size=size or 0 -- 0 means an infinite buffer, sometimes useful
|
|
for i=1,c.size do
|
|
c.data[i]=fill
|
|
end
|
|
local mt={
|
|
__index=function(t,k)
|
|
if type(k)=="number" then
|
|
local data=t.data[k]
|
|
if data then
|
|
return string.byte(data)
|
|
else
|
|
error("Index out of range!")
|
|
end
|
|
elseif type(k)=="string" then
|
|
local num=tonumber(k)
|
|
if num then
|
|
local data=t.data[num]
|
|
if data then
|
|
return data
|
|
else
|
|
error("Index out of range!")
|
|
end
|
|
else
|
|
error("Only number-strings and numbers can be indexed!")
|
|
end
|
|
else
|
|
error("Only number-strings and numbers can be indexed!")
|
|
end
|
|
end,
|
|
__newindex=function(t,k,v)
|
|
if type(k)~="number" then error("Can only set a buffers data with a numeric index!") end
|
|
local data=""
|
|
if type(v)=="string" then
|
|
data=v
|
|
elseif type(v)=="number" then
|
|
data=string.char(v)
|
|
else
|
|
-- try to normalize the data of type v
|
|
data=bin.normalizeData(v)
|
|
end
|
|
t:fillBuffer(k,data)
|
|
end,
|
|
__tostring=function(t)
|
|
return t:getData()
|
|
end,
|
|
}
|
|
function c:fillBuffer(a,data)
|
|
local len=#data
|
|
if len==1 then
|
|
self.data[a]=data
|
|
else
|
|
local i=a-1
|
|
for d in data:gmatch(".") do
|
|
i=i+1
|
|
if i>c.size then
|
|
return #data-i+a
|
|
end
|
|
self.data[i]=d
|
|
end
|
|
return #data-i+(a-1)
|
|
end
|
|
end
|
|
function c:getData(a,b,fmt) -- LATER
|
|
local dat=bin.new(table.concat(self.data,"",a,b))
|
|
local n=dat:getSize()
|
|
return dat:getBlock(fmt or "s",n)
|
|
end
|
|
function c:getSize()
|
|
return #self:getData()
|
|
end
|
|
setmetatable(c,mt)
|
|
return c
|
|
end
|
|
function bin:newDataBufferFromStream(pos,size,fill) -- fills with \0 or nul or with what you enter IF the nothing exists inside the bin file.
|
|
local s=self:getSize()
|
|
if not self.stream then error("Can only created a streamed buffer on a streamable file!") end
|
|
if s==0 then
|
|
self:write(string.rep("\0",pos+size))
|
|
end
|
|
self:setSeek(1)
|
|
local c=bin.newDataBuffer(size,fill)
|
|
rawset(c,"pos",pos)
|
|
rawset(c,"size",size)
|
|
rawset(c,"fill",fill)
|
|
rawset(c,"bin",self)
|
|
rawset(c,"sync",function(self)
|
|
local cur=self.bin:getSeek()
|
|
self.bin:setSeek(self.pos)
|
|
self.bin:write(self:getData(),size)
|
|
self.bin:setSeek(cur)
|
|
end)
|
|
c:fillBuffer(1,self:sub(pos,pos+size))
|
|
function c:fillBuffer(a,data)
|
|
local len=#data
|
|
if len==1 then
|
|
self.data[a]=data
|
|
self:sync()
|
|
else
|
|
local i=a-1
|
|
for d in data:gmatch(".") do
|
|
i=i+1
|
|
if i>c.size then
|
|
self:sync()
|
|
return #data-i+a
|
|
end
|
|
self.data[i]=d
|
|
end
|
|
self:sync()
|
|
return #data-i+(a-1)
|
|
end
|
|
end
|
|
return c
|
|
end
|
|
function bin:toDataBuffer()
|
|
local s=self:getSize()
|
|
-- if self:canStreamWrite() then
|
|
-- return self:newDataBufferFromStream(0,s)
|
|
-- end
|
|
local buf=bin.newDataBuffer(s)
|
|
local data=self:read(512)
|
|
local i=1
|
|
while data~=nil do
|
|
buf[i]=data
|
|
data=self:read(512)
|
|
i=i+512
|
|
end
|
|
return buf
|
|
end
|
|
function bin:getMD5Hash()
|
|
self:setSeek(1)
|
|
local len=self:getSize()
|
|
local md5=bin.md5.new()
|
|
local SIZE=2048
|
|
if len>SIZE then
|
|
local dat=self:read(SIZE)
|
|
while dat~=nil do
|
|
md5:update(dat)
|
|
dat=self:read(SIZE)
|
|
end
|
|
return bin.md5.tohex(md5:finish()):upper()
|
|
else
|
|
return bin.md5.sumhexa(self:getData()):upper()
|
|
end
|
|
end
|
|
function bin:getHash()
|
|
if self:getSize()==0 then
|
|
return "NaN"
|
|
end
|
|
n=32
|
|
local rand = randomGen:newND(1,self:getSize(),self:getSize())
|
|
local h,g={},0
|
|
for i=1,n do
|
|
g=rand:nextInt()
|
|
table.insert(h,bin.toHex(self:sub(g,g)))
|
|
end
|
|
return table.concat(h,'')
|
|
end
|
|
function bin:flipbits()
|
|
if self:canStreamWrite() then
|
|
self:setSeek(1)
|
|
for i=1,self:getSize() do
|
|
self:write(string.char(255-string.byte(self:sub(i,i))))
|
|
end
|
|
else
|
|
local temp={}
|
|
for i=1,#self.data do
|
|
table.insert(temp,string.char(255-string.byte(string.sub(self.data,i,i))))
|
|
end
|
|
self.data=table.concat(temp,'')
|
|
end
|
|
end
|
|
function bin:encrypt()
|
|
self:flipbits()
|
|
end
|
|
function bin:decrypt()
|
|
self:flipbits()
|
|
end
|
|
-- Use with small files!
|
|
function bin:gsub(...)
|
|
local data=self:getData()
|
|
local pos=self:getSeek()
|
|
self:setSeek(1)
|
|
self:write((data:gsub(...)) or data)
|
|
self:setSeek(loc)
|
|
end
|
|
function bin:gmatch(pat)
|
|
return self:getData():gmatch(pat)
|
|
end
|
|
function bin:match(pat)
|
|
return self:getData():match(pat)
|
|
end
|
|
function bin:trim()
|
|
local data=self:getData()
|
|
local pos=self:getSeek()
|
|
self:setSeek(1)
|
|
self:write(data:match'^()%s*$' and '' or data:match'^%s*(.*%S)')
|
|
self:setSeek(loc)
|
|
end
|
|
function bin:lines()
|
|
local t = {}
|
|
local function helper(line) table.insert(t, line) return '' end
|
|
helper((self:getData():gsub('(.-)\r?\n', helper)))
|
|
return t
|
|
end
|
|
function bin._lines(str)
|
|
local t = {}
|
|
local function helper(line) table.insert(t, line) return '' end
|
|
helper((str:gsub('(.-)\r?\n', helper)))
|
|
return t
|
|
end
|
|
function bin:wipe()
|
|
if self:canStreamWrite() then
|
|
self:close()
|
|
local c=bin.freshStream(self.file)
|
|
self.workingfile=c.workingfile
|
|
else
|
|
self.data=""
|
|
end
|
|
self:setSeek(1)
|
|
end
|
|
function bin:fullTrim(empty)
|
|
local t=self:lines()
|
|
for i=#t,1,-1 do
|
|
t[i]=bin._trim(t[i])
|
|
if empty then
|
|
if t[i]=="" then
|
|
table.remove(t,i)
|
|
end
|
|
end
|
|
end
|
|
self:wipe()
|
|
self:write(table.concat(t,"\n"))
|
|
end
|
|
require("bin.support.extraBlocks") -- registered blocks that you can use
|
|
if love then
|
|
function bin.load(file,s,r)
|
|
content, size = love.filesystem.read(file)
|
|
local temp=bin.new(content)
|
|
temp.filepath=file
|
|
return temp
|
|
end
|
|
function bin:tofile(filename)
|
|
if not(filename) or self.Stream then return nil end
|
|
love.filesystem.write(filename,self.data)
|
|
end
|
|
function bin.stream(file)
|
|
return bin.newStreamFileObject(love.filesystem.newFile(file))
|
|
end
|
|
function bin:getSize(fmt)
|
|
local len=0
|
|
if self.stream then
|
|
local len=self.workingfile:getSize()
|
|
else
|
|
len=#self.data
|
|
end
|
|
if fmt=="%b" then
|
|
return bin.toB64()
|
|
elseif fmt then
|
|
return string.format(fmt, len)
|
|
else
|
|
return len
|
|
end
|
|
end
|
|
function bin:getSeek()
|
|
if self.stream then
|
|
return self.workingfile:tell()+1
|
|
else
|
|
return self.pos
|
|
end
|
|
end
|
|
function bin:setSeek(n)
|
|
if self.stream then
|
|
self.workingfile:seek(n-1)
|
|
else
|
|
self.pos=n
|
|
end
|
|
end
|
|
function bin:seek(n)
|
|
if self.stream then
|
|
self.workingfile:seek(n)
|
|
else
|
|
if not n then return self.pos end
|
|
if #self.data-(self.pos-1)<n then
|
|
print(n-((#self.data)-(self.pos-1)))
|
|
self:write(string.rep("\0",n-((#self.data)-(self.pos-1))))
|
|
return
|
|
end
|
|
self.pos=self.pos+n
|
|
end
|
|
end
|
|
function bin:close()
|
|
self.workingfile:close()
|
|
end
|
|
end
|