Ryan cf22651949 Added intergration loveManager
Adds multi.intergrations.loveManager,lua
Created an example file for you to look at
2017-06-24 22:46:44 -04:00

3208 lines
85 KiB
Lua
Raw Blame History

--[[TODO
+Better compatiblity with streamables
+Add Data Compression
+Add Encryption(better)
+Create full documentation
+Enhance VFS stuff
]]
bin={}
bin.Version={4,5,0}
bin.stage='stable'
bin.help=[[
For a list of features do print(bin.Features)
For a list of changes do print(bin.changelog)
For current version do print(bin.Version)
For current stage do print(bin.stage)
For help do print(bin.help) :D
]]
bin.credits=[[
Credits:
Crafted by, Ryan Ward
lzw,bit shift, and b64 conversion are not mine
]]
bin.Features=bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3]..' '..bin.stage..[[
print(bin.Features) And you get this thing
print(bin.Version) ]]..bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3]..[[ <-- your version
print(bin.Changlog) -- gives you a list of changes
print(bin.stage) ]]..bin.stage..[[ <-- your stage
Purpose
-------
Made to assist with the manipulation of binary data and efficent data management
Created by: Ryan Ward
Full documentation with examples of every function soon to come!!!
This is a brief doc for reference
Misc
----
nil = log(data,name,fmt) -- data is the text that you want to log to a file, the name argument only needs to be called with the first log. It tells where to log to. If name is used again it will change the location of the log file.
string,string,string = bin.getLuaVersion() -- returns PUC/JIT,major,minor
Constructors
------------
binobj = bin.load(filename,s,r) -- creates binobj from file in s and r nil then reads entire file but if not s is the start point of reading and r is either the #to read after s or from s to '#' (like string.sub())
binobj = bin.new(string data) -- creates binobj from a string
binobj = bin.stream(file,lock) -- creates a streamable binobj lock is defult to true if locked file is read only
binobj = bin.newTempFile(data) -- creates a tempfile in stream mode
bitobj = bits.new(n) -- creates bitobj from a number
vfs = bin.newVFS() -- creates a new virtual file system --Beta
vfs = bin.loadVFS(path) -- loads a saved .lvfs file --Beta
buf = bin:newDataBuffer(s) -- creates a databuffer
binobj = bin.bufferToBin(b) -- converts a buffer object to a bin object
buf = bin.binToBuffer(b) -- converts a bin object to a buffer obj
buf = bin:getDataBuffer(a,b) -- gets a speical buffer that opperates on a streamed file. It works just like a regular data buffer
blockWriter = bin.newNamedBlock(indexSize) -- returns a block writer object index size is the size of the index where labels and pointers are stored
blockWriter = bin.newStreamedNamedBlock(indexSize,path) -- returns a streamed version of the above path is the path to write the file
blockReader = bin.loadNamedBlock(path) -- returns a block reader object, path is where the file is located
blockHandler= bin.namedBlockManager(arg) -- returns a block handler object, if arg is a string it will loade a named block file, if its a number or nil it will create a nambed block object
Note: the blockWriter that isn't streamed needs to have tofile(path) called on it to write it to a file
Note: the streamed blockWriter must have the close method used when you are done writing to it!
Helpers
-------
string = bin.randomName(n,ext) -- creates a random file name if n and ext is nil then a random length is used, and '.tmp' extension is added
string = bin.NumtoHEX(n) -- turns number into hex
binobj = bin.HEXtoBin(s)*D -- turns hex data into binobj
string = bin.HEXtoStr(s)*D -- turns hex data into string/text
string = bin.tohex(s) -- turns string to hex
string = bin.fromhex(s) -- turns hex to string
string = bin.endianflop(data) -- flips the high order bits to the low order bits and viseversa
string = bin.getVersion() -- returns the version as a string
string = bin.escapeStr(str) -- system function that turns functions into easy light
string = bin.ToStr(tab) -- turns a table into a string (even functions are dumped; used to create compact data files)
nil = bin.packLLIB(name,tab,ext) -- turns a bunch of 'files' into 1 file tab is a table of file names, ext is extension if nil .llib is used Note: Currently does not support directories within .llib
nil = bin.unpackLLIB(name,exe,todir,over,ext) -- takes that file and makes the files Note: if exe is true and a .lua file is in the .llib archive than it is ran after extraction ext is extension if nil .llib is used
boolean = bin.fileExist(path) -- returns true if the file exist false otherwise
boolean*= bin.closeto(a,b,v) -- test data to see how close it is (a,b=tested data v=#difference (v must be <=255))
String = bin.textToBinary(txt) -- turns text into binary data 10101010's
binobj = bin.decodeBits(bindata) -- turns binary data into text
string = bin.trimNul(s) -- terminates string at the nul char
number = bin.getIndexSize(tab) -- used to get the index size of labels given to a named block
string = bits.numToBytes(num,occ) -- returns the number in base256 string data, occ is the space the number will take up
Assessors
---------
nil*** = binobj:tofile(filename) -- writes binobj data as a file
binobj* = binobj:clone() -- clones and returns a binobj
number* = binobj:compare(other binobj,diff) -- returns 0-100 % of simularity based on diff factor (diff must be <=255)
string = binobj:sub(a,b) -- returns string data like segment but dosen't alter the binobject
num,num = binobj:tonumber(a,b) -- converts from a-b (if a and b are nil it uses the entire binobj) into a base 10 number so 'AXG' in data becomes 4675649 returns big,little endian
number = binobj:getbyte(n) -- gets byte at location and converts to base 10 number
bitobj = binobj:tobits(i) -- returns the 8bits of data as a bitobj Ex: if value of byte was a 5 it returns a bitobj with a value of: '00000101'
string = binobj:getHEX(a,b) -- gets the HEX data from 'a' to 'b' if both a,b are nil returns entire file as hex
a,b = binobj:scan(s,n,f) -- searches a binobj for 's'; n is where to start looking, 'f' is weather or not to flip the string data entered 's'
string = binobj:streamData(a,b) -- reads data from a to b or a can be a data handle... I will explain this and more in offical documentation
string# = binobj:streamread(a,b) -- reads data from a stream object between a and b (note: while other functions start at 1 for both stream and non stream 0 is the starting point for this one)
boolean = binobj:canStreamWrite() -- returns true if the binobj is streamable and isn't locked
string = bitobj:conv(n) -- converts number to binary bits (system used)
binobj = bitobj:tobytes() -- converts bit obj into a string byte (0-255)
number = bitobj:tonumber() -- converts '10101010' to a number
boolean = bitobj:isover() -- returns true if the bits exceed 8 bits false if 8 or less
string = bitobj:getBin() -- returns the binary 10100100's of the data as a string
string = binobj:getHash(n) -- returns a Hash of a file (This is my own method of hashing btw) n is the length you want the hash to be
string = binobj:getData() -- returns the bin object as a string
depends = blockReader:getBlock(name) -- returns the value associated with the name, values can be any lua data except userdata
Mutators (Changes affect the actual object or if streaming the actual file) bin:remove()
--------
nil = binobj:setEndOfFile(n) -- sets the end of a file
nil = binobj:reverse() -- reverses binobj data ex: hello --> olleh
nil = binobj:flipbits() -- flips the binary bits
nil** = binobj:segment(a,b) -- gets a segment of the binobj data works just like string.sub(a,b) without str
nil* = binobj:insert(a,i) -- inserts i (string or number(converts into string)) in position a
nil* = binobj:parseN(n) -- removes ever (nth) byte of data
nil = binobj:getlength() -- gets length or size of binary data
nil* = binobj:shift(n) -- shift the binary data by n positive --> negitive <--
nil* = binobj:delete(a,b) -- deletes part of a binobj data Usage: binobj:delete(#) deletes at pos # binobj:delete(#1,#2) deletes from #1 to #2 binobj:delete('string') deletes all instances of 'byte' as a string Use string.char(#) or '\#' to get byte as a string
nil* = binobj:encrypt(seed) -- encrypts data using a seed, seed may be left blank
nil* = binobj:decrypt(seed) -- decrypts data encrypted with encrypt(seed)
nil* = binobj:shuffle() -- Shuffles the data randomly Note: there is no way to get it back!!! If original is needed clone beforehand
nil** = binobj:mutate(a,i) -- changes position a's value to i
nil = binobj:merge(o,t) -- o is the binobj you are merging if t is true it merges the new data to the left of the binobj EX: b:merge(o,true) b='yo' o='data' output: b='datayo' b:merge(o) b='yo' o='data' output: b='yodata'
nil* = binobj:parseA(n,a,t) -- n is every byte where you add, a is the data you are adding, t is true or false true before false after
nil = binobj:getHEX(a,b) -- returns the HEX of the bytes between a,b inclusive
nil = binobj:cryptM() -- a mirrorable encryptor/decryptor
nil = binobj:addBlock(d,n) -- adds a block of data to a binobj s is size d is data e is a bool if true then encrypts string values. if data is larger than 'n' then data is lost. n is the size of bytes the data is Note: n is no longer needed but you must use getBlock(type) to get it back
nil = binobj:getBlock(t,n) -- gets block of code by type
nil = binobj:seek(n) -- used with getBlock EX below with all 3
nil* = binobj:morph(a,b,d) -- changes data between point a and b, inclusive, to d
nil = binobj:fill(n,d) -- fills binobj with data 'd' for n
nil = binobj:fillrandom(n) -- fills binobj with random data for n
nil = binobj:shiftbits(n) -- shifts all bits by n amount
nil = binobj:shiftbit(n,i) -- shifts a bit ai index i by n
nil# = binobj:streamwrite(d,n) -- writes to the streamable binobj d data n position
nil# = binobj:open() -- opens the streamable binobj
nil# = binobj:close() -- closes the streamable binobj
nil = binobj:wipe() -- erases all data in the file
nil* = binobj:tackB(d) -- adds data to the beginning of a file
nil = binobj:tackE(d) -- adds data to the end of a file
nil = binobj:parse(n,f) -- loops through each byte calling function 'f' with the args(i,binobj,data at i)
nil = binobj:flipbit(i) -- flips the binary bit at position i
nil* = binobj:gsub() -- just like string:gsub(), but mutates self
nil = blockWriter:addNamedBlock(name,value) -- writes a named block to the file with name 'name' and the value 'value'
Note: numbers are written in Big-endian use bin.endianflop(d) to filp to Little-endian
Note: binobj:tonumber() returns big,little endian so if printing do: b,l=binobj:tonumber() print(l) print(b)
nil = bitobj:add(i) -- adds i to the bitobj i can be a number (base 10) or a bitobj
nil = bitobj:sub(i) -- subs i to the bitobj i can be a number (base 10) or a bitobj
nil = bitobj:multi(i) -- multiplys i to the bitobj i can be a number (base 10) or a bitobj
nil = bitobj:div(i) -- divides i to the bitobj i can be a number (base 10) or a bitobj
nil = bitobj:flipbits() -- filps the bits 1 --> 0, 0 --> 1
string = bitobj:getBin() -- returns 1's & 0's of the bitobj
# stream objects only
* not compatible with stream files
** works but do not use with large files or it works to some degree
*** in stream objects all changes are made directly to the file, so there is no need to do tofile()
*D
]]
bin.Changelog=[[
Version.Major.Minor
-------------------------
1.0.0 : initial release load/new/tofile/clone/closeto/compare/sub/reverse/flip/segment/insert/insert/parseN/getlength/shift
1.0.1 : update Delete/tonumber/getbyte/
1.0.2 : update Changed how delete works. Added encrypt/decrypt/shuffle
1.0.3 : update Added bits class, Added in bin: tobit/mutate/parseA Added in bits: add/sub/multi/div/isover/tobyte/tonumber/flip
1.0.4 : update Changed tobyte() to tobytes()/flipbit() to flipbits() and it now returns a binobj not str Added bin:merge
1.0.5 : update Changed bin.new() now hex data can be inserted EX: bin.new('0xFFC353D') Added in bin: getHEX/cryptM/addBlock/getBlock/seek
1.0.6 : update Added bin.NumtoHEX/bin:getHEX/bin.HEXtoBin/bin.HEXtoStr/bin.tohex/bin.fromhex
1.0.7 : update Added bin:morph/bin.endianflop/bin:scan/bin.ToStr
1.0.8 : update Added bin:fill/bin:fillrandom
1.1.0 : update Added bin.packLLIB/bin.unpackLLIB
1.2.0 : update Updated llib files
1.3.0 : Update Changed bin.unpackLLIB and bin.load() Added: bin.fileExist
1.4.0 : Update Changed bin.unpackLLIB bin.packLLIB Added: bin:shiftbits(n) bin:shiftbit(n,i)
Woot!!! Version 2
2.0.0 HUGE UPDATE Added Streamable files!!! lua 5.1, 5.2 and 5.3 compatable!!!
#binobj is the same as binobj:getlength() but only works in 5.2 and 5.3, in 5.1 just use getlength() or getSize() for compatibility
Now you can work with gigabyte sized data without memory crashes(streamable files[WIP]).
Stream Compatible methods:
sub(a,b)
getlength()
tofile(filename)
flipbits()
tonumber(a,b)
getbyte(n)
segment(a,b)
parse(n,f)
tobits(i)
reverse()
flipbit(i)
cryptM()
getBlock(t,n)
addBlock(d,n)
shiftbits(n)
shiftbit(n,i)
getHEX(a,b)
Added functions in this version:
binobj:streamwrite(d,n)
binobj:open()
binobj:close()
binobj:tackB(d)
binobj:tackE(d)
binobj:parse(n,f)
binobj:flipbit(i)
bin.stream(file)
binobj:streamData(a,b)
bin.getVersion()
bin.escapeStr(str)
binobj:streamread(a,b)
binobj:canStreamWrite()
binobj:wipe()
Woot!!! Version 3
3.0.0 HUGE UPDATE!!!
Added: bin.newVFS() bin.loadVFS() bin.textToBinary(txt) bin.decodeBits(bindata) bitobj:getBin()
Updated: bin.addBlock() <-- Fixed error with added features to the bits.new() function that allow for new functions to work
Notice: The bin library now requires the utils library!!! Put utils.lua in the lua/ directory
3.1.0
Added: bin.newTempFile(data) binobj:setEndOfFile(n) bin.randomName(n,ext)
Updated: bin:tackE() bin:fill() bin:fillrandom() are now stream compatible!
Notice: bin:setEndOfFile() only works on streamable files!
3.1.1
Added: bin.trimNul(s) bin:gsub()
3.1.2
Added: log(data,name,fmt)
In secret something is brewing...
3.1.3
Added: bin:getHash(n)
3.2.1
Added: bin.encryptA(data,seed), bin.decryptA(data,seed), bin.encryptB(data,seed), bin.decryptB(data,seed), bin:flush()
Updated: bin:encrypt(seed) and bin:decrypt(seed)
Fixed: bin:shiftbit() not working right with streamable files
3.2.2
Fixed: bits.new() -- minor mistake huge error
3.2.3
General bug fixes
Changed how bin.ToStr(t) -- functions are no longer valid data types
3.3.0
Added:
bin:getSize() -- same as bin:getlength() just makes more sense. bin:getlength() is still valid and always will be.
bin.newLink() -- creates a link to a file object... Its like opening a file without opening it... Lua can only open a maximum of 200 files so use links if you will be going beyond that or make sure to close your files
bin.getHash2(h,n) -- 'h' hash size 8bit,16bit,32bit,64bit, 128bit, 100000bit whatever. is a number 'n' is the segmentation size defualt is 1024 greater numbers result in faster hashes but eaiser to forge hashes
3.4.1:(7/22/2016) NOTE: I started to add dates so I can see my work flow
Added:
binobj:getData() -- returns bin object as a string
bin:newDataBuffer(s)
Fixed: binobj:tonumber(a,b)
4.0.0:(7/23/2016)
Added:
bin.bufferToBin(b)
bin.binToBuffer(b)
bin.getLuaVersion()
bin.newNamedBlock(indexSize)
bin.newStreamedNamedBlock(indexSize,path)
bin.loadNamedBlock(path)
bin.getIndexSize(tab)
bits.numToBytes(num,occ)
4.1.0:(11/2/2016) NOTE: I took quite a long break due to college lol
Added:
bin.namedBlockManager(name)
Allows for a new way to use NamedBlocks
Example usage:
test=bin.namedBlockManager()
test["name"]="Ryan" -- My name lol
test["age"]=21 -- my age lol
test:tofile("test.dat")
--Now lets load the data we created
test2=bin.namedBlockManager("test.dat")
print(test2["name"])
print(test2["age"])
Changed:
bin.newNamedBlock(indexSize)
Now allows for indexSize to be nil and dynamacally adds to the size of the index
Fixed:
bin.loadNamedBlock(name)
Issue with indexing
TODO:
Allow streamed files to have expanding indexes
4.2.0:(12/21/2016)
Added:
bin.gcd(m,n) *takes number types returns a number
gets the greatest common denominator between 2 numbers m and n
bin.numToFraction(num) *takes number type returns a string type
converts a decimal to a fraction
so 5.5 would become 11/2
bin.doubleToString(double) *takes number type returns string
converts a double to a string
bin.stringToDouble(str) *takes string type returns number type
converts the doublestring into a number
NOTE: this string can be 2 lengths! Either 9 bytes or 25 bytes... depending on the precision needed the program will convert the data
Also: the miniheader -/+ is for 9byte doubles the miniheader _/=(same keys as -/+ on an American keyboard) is for 25byte doubles
Changed:
bits.numToBytes(n,fit,func)
added argument func which is called when the number n takes up more space than size 'fit'
passes a ref table with keys num and fit, modifying these effects the output.
Note: If you change ref.fit make sure to make ref.num fits by adding \0 to the beginning of the numberstring
TODO:
add more useful features :P
4.2.1:(12/23/2016)
Added:
bin.decompress(comp) lzw commpression
bin.compress(uncomp) lzw decommpression
bin:segmentedRead(size,func)
4.3.0:(12/26/2016)
Added:
bin.tob64(data)
converts string data to b64 data
bin.fromb64(data)
converts b64 data to string data
bin:getB64()
returns b64 data from binobj
bits.lsh(value,shift) bit lshift
bits.rsh(value,shift) bit rshift
bits.bit(x,b) bit thing
bits.lor(x,y) or
Changed:
bin.new(data,hex,b64) hex if true treats data as hexdata, b64 if true treats data like b64data
Now allows b64 data to be used in construction of a bin file
4.4.0:(1/1/2017)
Added:
sinkobj=bin:newSink()
nil=sinkobj:tackE(data)
adds data into the sink, same method that binobj and streamobjs have. This does what you would expest the binobj to do but much quicker
nil=sinkobj:tofile(path)
creates a file containing the contents of the sink
str=sinkobj:getData()
returns the data of the sink as a string
nil=sinkobj:reset()
Clears the sink
4.4.1:(1/2/2017)
Changed:
bin.stream(file,lock)
Modified stream files so that multiple streams can link to one file by sharing handles
4.4.2:(1/10/2017)
Added:
bin.freshStream(file)
creates a stream object that wipes all data if the file already exists and readys the object for writing. In short it's doing: bin.new():tofile(file) return bin.stream(file,false)
-- I found myself doing that so much I made a method to simplify the process
4.5.0:(3/31/2017)
Added:
bin:getDataBuffer(a,b) -- a and b are the location to open on the streamed object they are not required though
-- If left out the entire file is open to used as a buffer! Even a empty streamed file works. Be sure to fill the buffer before trying to write to a location without data
-- Index 1 is the start regardless of where you open up the file
Note: Only works on streamed files! Use bin:newDataBuffer(s) to use the non streamed version
]]
bin.data=''
bin.t='bin'
bin.__index = bin
bin.__tostring=function(self) return self:getData() end
bin.__len=function(self) return self:getlength() end
bits={}
bits.data=''
bits.t='bits'
bits.__index = bits
bits.__tostring=function(self) return self.data end
bits.__len=function(self) return (#self.data)/8 end
bin.lastBlockSize=0
bin.streams={} -- allows for multiple stream objects on one file... tricky stuff lol
--[[----------------------------------------
Links
------------------------------------------]]
function bin.newLink(path)
if not path then
error("Must include a path when using a link!")
end
local c={}
c.path=path
c.tempfile={}
local mt={
__tostring=function(self)
if self:getlength()>2048 then
--
end
end,
__len=function(self)
return self:getlength()
end
}
function c:getlength()
--
end
end
--[[----------------------------------------
utils
------------------------------------------]]
function cleanName(name)
name=name:gsub("\\","")
name=name:gsub("/","")
name=name:gsub(":","")
name=name:gsub("*","")
name=name:gsub("%?","")
name=name:gsub("\"","''")
name=name:gsub("<","")
name=name:gsub(">","")
name=name:gsub("|","")
return name
end
function math.numfix(n,x)
local str=tostring(n)
if #str<x then
str=('0'):rep(x-#str)..str
end
return str
end
function bin.stripFileName(path)
path=path:gsub("\\","/")
local npath=path:reverse()
a=npath:find("/",1,true)
npath=npath:sub(a)
npath=npath:reverse()
return npath
end
function io.mkDir(dirname)
os.execute('mkdir "' .. dirname..'"')
end
function string.lines(str)
local t = {}
local function helper(line) table.insert(t, line) return '' end
helper((str:gsub('(.-)\r?\n', helper)))
return t
end
function log(data,name,fmt)
if name then
name=cleanName(name)
end
if not bin.logger then
bin.logger = bin.stream(name or 'lua.log',false)
elseif bin.logger and name then
bin.logger:close()
bin.logger = bin.stream(name or 'lua.log',false)
end
local d=os.date('*t',os.time())
bin.logger:tackE((fmt or '['..math.numfix(d.month,2)..'-'..math.numfix(d.day,2)..'-'..d.year..'|'..math.numfix(d.hour,2)..':'..math.numfix(d.min,2)..':'..math.numfix(d.sec,2)..']\t')..data..'\n')
end
function io.mkFile(filename,data,tp)
if not(tp) then tp='wb' end
if not(data) then data='' end
file = io.open(filename, tp)
if file==nil then return end
file:write(data)
file:close()
end
function io.getWorkingDir()
return io.popen'cd':read'*l'
end
function getAllItems(dir)
local t=os.capture("cd \""..dir.."\" & dir /a-d | find",true):lines()
return t
end
function os._getOS()
if package.config:sub(1,1)=='\\' then
return 'windows'
else
return 'unix'
end
end
function os.getOS(t)
if not t then
return os._getOS()
end
if os._getOS()=='unix' then
fh,err = io.popen('uname -o 2>/dev/null','r')
if fh then
osname = fh:read()
end
if osname then return osname end
end
local winver='Unknown Version'
local a,b,c=os.capture('ver'):match('(%d+).(%d+).(%d+)')
local win=a..'.'..b..'.'..c
if type(t)=='string' then
win=t
end
if win=='4.00.950' then
winver='95'
elseif win=='4.00.1111' then
winver='95 OSR2'
elseif win=='4.00.1381' then
winver='NT 4.0'
elseif win=='4.10.1998' then
winver='98'
elseif win=='4.10.2222' then
winver='98 SE'
elseif win=='4.90.3000' then
winver='ME'
elseif win=='5.00.2195' then
winver='2000'
elseif win=='5.1.2600' then
winver='XP'
elseif win=='5.2.3790' then
winver='Server 2003'
elseif win=='6.0.6000' then
winver='Vista/Windows Server 2008'
elseif win=='6.0.6002' then
winver='Vista SP2'
elseif win=='6.1.7600' then
winver='7/Windows Server 2008 R2'
elseif win=='6.1.7601' then
winver='7 SP1/Windows Server 2008 R2 SP1'
elseif win=='6.2.9200' then
winver='8/Windows Server 2012'
elseif win=='6.3.9600' then
winver='8.1/Windows Server 2012'
elseif win=='6.4.9841' then
winver='10 Technical Preview 1'
elseif win=='6.4.9860' then
winver='10 Technical Preview 2'
elseif win=='6.4.9879' then
winver='10 Technical Preview 3'
elseif win=='10.0.9926' then
winver='10 Technical Preview 4'
end
return 'Windows '..winver
end
function os.capture(cmd, raw)
local f = assert(io.popen(cmd, 'r'))
local s = assert(f:read('*a'))
f:close()
if raw then return s end
s = string.gsub(s, '^%s+', '')
s = string.gsub(s, '%s+$', '')
s = string.gsub(s, '[\n\r]+', ' ')
return s
end
function io.scanDir(directory)
directory=directory or io.getDir()
local i, t, popen = 0, {}, io.popen
if os.getOS()=='unix' then
for filename in popen('ls -a "'..directory..'"'):lines() do
i = i + 1
t[i] = filename
end
else
for filename in popen('dir "'..directory..'" /b'):lines() do
i = i + 1
t[i] = filename
end
end
return t
end
function io.getDir(dir)
if not dir then return io.getWorkingDir() end
if os.getOS()=='unix' then
return os.capture('cd '..dir..' ; cd')
else
return os.capture('cd '..dir..' & cd')
end
end
function string.split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = '(.-)' .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= '' then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
function io.fileExists(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 io.getDirectories(dir,l)
if dir then
dir=dir..'\\'
else
dir=''
end
local temp2=io.scanDir(dir)
for i=#temp2,1,-1 do
if io.fileExists(dir..temp2[i]) then
table.remove(temp2,i)
elseif l then
temp2[i]=dir..temp2[i]
end
end
return temp2
end
function io.getFiles(dir,l)
if dir then
dir=dir..'\\'
else
dir=''
end
local temp2=io.scanDir(dir)
for i=#temp2,1,-1 do
if io.dirExists(dir..temp2[i]) then
table.remove(temp2,i)
elseif l then
temp2[i]=dir..temp2[i]
end
end
return temp2
end
function io.readFile(file)
local f = io.open(file, 'rb')
local content = f:read('*all')
f:close()
return content
end
function table.print(tbl, indent)
if not indent then indent = 0 end
for k, v in pairs(tbl) do
formatting = string.rep(' ', indent) .. k .. ': '
if type(v) == 'table' then
print(formatting)
table.print(v, indent+1)
else
print(formatting .. tostring(v))
end
end
end
function io.dirExists(strFolderName)
strFolderName = strFolderName or io.getDir()
local fileHandle, strError = io.open(strFolderName..'\\*.*','r')
if fileHandle ~= nil then
io.close(fileHandle)
return true
else
if string.match(strError,'No such file or directory') then
return false
else
return true
end
end
end
function io.getFullName(name)
local temp=name or arg[0]
if string.find(temp,'\\',1,true) or string.find(temp,'/',1,true) then
temp=string.reverse(temp)
a,b=string.find(temp,'\\',1,true)
if not(a) or not(b) then
a,b=string.find(temp,'/',1,true)
end
return string.reverse(string.sub(temp,1,b-1))
end
return temp
end
function io.getName(file)
local name=io.getFullName(file)
name=string.reverse(name)
a,b=string.find(name,'.',1,true)
name=string.sub(name,a+1,-1)
return string.reverse(name)
end
function io.getPathName(path)
return path:sub(1,#path-#io.getFullName(path))
end
function table.merge(t1, t2)
for k,v in pairs(t2) do
if type(v) == 'table' then
if type(t1[k] or false) == 'table' then
table.merge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
function io.splitPath(str)
return string.split(str,'[\\/]+')
end
function io.pathToTable(path)
local p=io.splitPath(path)
local temp={}
temp[p[1]]={}
local last=temp[p[1]]
for i=2,#p do
snd=last
last[p[i]]={}
last=last[p[i]]
end
return temp,last,snd
end
function io.parseDir(dir,t)
io.tempFiles={}
function _p(dir)
local dirs=io.getDirectories(dir,true)
local files=io.getFiles(dir,true)
for i=1,#files do
p,l,s=io.pathToTable(files[i])
if t then
s[io.getFullName(files[i])]=io.readFile(files[i])
else
s[io.getFullName(files[i])]=io.open(files[i],'r+')
end
table.merge(io.tempFiles,p)
end
for i=1,#dirs do
table.merge(io.tempFiles,io.pathToTable(dirs[i]))
_p(dirs[i],t)
end
end
_p(dir)
return io.tempFiles
end
function io.parsedir(dir,f)
io.tempFiles={}
function _p(dir,f)
local dirs=io.getDirectories(dir,true)
local files=io.getFiles(dir,true)
for i=1,#files do
if not f then
table.insert(io.tempFiles,files[i])
else
f(files[i])
end
end
for i=1,#dirs do
_p(dirs[i],f)
end
end
_p(dir,f)
return io.tempFiles
end
--[[----------------------------------------
Random
Not all of this is mine
------------------------------------------]]
--[[------------------------------------
RandomLua v0.3.1
Pure Lua Pseudo-Random Numbers Generator
Under the MIT license.
copyright(c) 2011 linux-man
--]]------------------------------------
local math_floor = math.floor
local function normalize(n) --keep numbers at (positive) 32 bits
return n % 0x80000000
end
local function bit_and(a, b)
local r = 0
local m = 0
for m = 0, 31 do
if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end
if a % 2 ~= 0 then a = a - 1 end
if b % 2 ~= 0 then b = b - 1 end
a = a / 2 b = b / 2
end
return normalize(r)
end
local function bit_or(a, b)
local r = 0
local m = 0
for m = 0, 31 do
if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end
if a % 2 ~= 0 then a = a - 1 end
if b % 2 ~= 0 then b = b - 1 end
a = a / 2 b = b / 2
end
return normalize(r)
end
local function bit_xor(a, b)
local r = 0
local m = 0
for m = 0, 31 do
if a % 2 ~= b % 2 then r = r + 2^m end
if a % 2 ~= 0 then a = a - 1 end
if b % 2 ~= 0 then b = b - 1 end
a = a / 2 b = b / 2
end
return normalize(r)
end
local function seed()
--return normalize(tonumber(tostring(os.time()):reverse()))
return normalize(os.time())
end
--Mersenne twister
mersenne_twister = {}
mersenne_twister.__index = mersenne_twister
function mersenne_twister:randomseed(s)
if not s then s = seed() end
self.mt[0] = normalize(s)
for i = 1, 623 do
self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i)
end
end
function mersenne_twister:random(a, b)
local y
if self.index == 0 then
for i = 0, 623 do
--y = bit_or(math_floor(self.mt[i] / 0x80000000) * 0x80000000, self.mt[(i + 1) % 624] % 0x80000000)
y = self.mt[(i + 1) % 624] % 0x80000000
self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2))
if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end
end
end
y = self.mt[self.index]
y = bit_xor(y, math_floor(y / 0x800))
y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680))
y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000))
y = bit_xor(y, math_floor(y / 0x40000))
self.index = (self.index + 1) % 624
if not a then return y / 0x80000000
elseif not b then
if a == 0 then return y
else return 1 + (y % a)
end
else
return a + (y % (b - a + 1))
end
end
function twister(s)
local temp = {}
setmetatable(temp, mersenne_twister)
temp.mt = {}
temp.index = 0
temp:randomseed(s)
return temp
end
--Linear Congruential Generator
linear_congruential_generator = {}
linear_congruential_generator.__index = linear_congruential_generator
function linear_congruential_generator:random(a, b)
local y = (self.a * self.x + self.c) % self.m
self.x = y
if not a then return y / 0x10000
elseif not b then
if a == 0 then return y
else return 1 + (y % a) end
else
return a + (y % (b - a + 1))
end
end
function linear_congruential_generator:randomseed(s)
if not s then s = seed() end
self.x = normalize(s)
end
function lcg(s, r)
local temp = {}
setmetatable(temp, linear_congruential_generator)
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
if r then
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
end
temp:randomseed(s)
return temp
end
-- Multiply-with-carry
multiply_with_carry = {}
multiply_with_carry.__index = multiply_with_carry
function multiply_with_carry:random(a, b)
local m = self.m
local t = self.a * self.x + self.c
local y = t % m
self.x = y
self.c = math_floor(t / m)
if not a then return y / 0x10000
elseif not b then
if a == 0 then return y
else return 1 + (y % a) end
else
return a + (y % (b - a + 1))
end
end
function multiply_with_carry:randomseed(s)
if not s then s = seed() end
self.c = self.ic
self.x = normalize(s)
end
function mwc(s, r)
local temp = {}
setmetatable(temp, multiply_with_carry)
temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C
if r then
if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes.
elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC
end
temp.ic = temp.c
temp:randomseed(s)
return temp
end
-- Little bind for the methods: My code starts
randomGen={}
randomGen.__index=randomGen
function randomGen:new(s)
local temp={}
setmetatable(temp,randomGen)
temp[1]=twister()
temp[2]=lcg()
temp[3]=mwc()
temp.pos=1
for i=1,3 do
temp[i]:randomseed(s)
end
return temp
end
function randomGen:randomseed(s)
self.pos=1
self[1]:randomseed(s)
self[2]:randomseed(s)
self[3]:randomseed(s)
end
function randomGen:randomInt(a,b)
local t=self[self.pos]:random(a,b)
self.pos=self.pos+1
if self.pos>3 then
self.pos=1
end
return t
end
function randomGen:newND(a,b,s)
if not(a) or not(b) then error('You must include a range!') end
local temp=randomGen:new(s)
temp.a=a
temp.b=b
temp.range=b-a+1
temp.dups={no=0}
function temp:nextInt()
local t=self:randomInt(self.a,self.b)
if self.dups[t]==nil then
self.dups[t]=true
self.dups.no=self.dups.no+1
else
return self:nextInt()
end
if self.dups.no==self.range then
function self:nextInt()
return 1,true
end
return t
else
return t
end
end
function temp:nextIInt()
return function() return self:nextInt() end
end
return temp
end
lzw = {}
function lzw.encode(uncompressed) -- string
local dictionary, result, dictSize, w, c = {}, {}, 255, ""
for i = 0, 255 do
dictionary[string.char(i)] = i
end
for i = 1, #uncompressed do
c = string.sub(uncompressed, i, i)
if dictionary[w .. c] then
w = w .. c
else
table.insert(result, dictionary[w])
dictSize = dictSize + 1
dictionary[w .. c] = dictSize
w = c
end
end
if w ~= "" then
table.insert(result, dictionary[w])
end
return result
end
function lzw.decode(compressed) -- table
local dictionary, dictSize, entry, result, w, k = {}, 255, "", "", ""
for i = 0, 255 do
dictionary[i] = string.char(i)
end
for i = 1, #compressed do
k = compressed[i]
if dictionary[k] then
entry = dictionary[k]
elseif k == dictSize then
entry = w .. string.sub(w, 1, 1)
else
return nil, i
end
result = result .. entry
dictionary[dictSize] = w .. string.sub(entry, 1, 1)
dictSize = dictSize + 1
w = entry
end
return result
end
--[[----------------------------------------
BIN
------------------------------------------]]
function bin:newSink()
local c={}
c.data={}
c.name="sinkobj"
c.num=1
c.type="sink"
function c:tackE(data)
self.data[self.num]=data
self.num=self.num+1
end
function c:tofile(path)
bin.new(table.concat(self.data)):tofile(path)
end
function c:getData()
return table.concat(self.data)
end
function c:reset()
self.data={}
end
function c:close()
-- does nothing lol
end
return c
end
function bin:segmentedRead(size,func)
local mSize=self:getSize()
local pSize=size
local iter=math.ceil(mSize/pSize)
for i=0,iter-1 do
func(self:sub((i*pSize)+1,(i+1)*pSize))
end
end
function bin.compress(uncomp,n)
n=n or 9
local cipher = lzw.encode(uncomp)
local dat={}
for i=1,#cipher do
local fix=bits.new(cipher[i]).data:match("0*(%d+)")
if cipher[i]==0 then
fix=string.rep("0",n)
end
fix=string.rep("0",n-#fix)..fix
table.insert(dat,fix)
end
str=table.concat(dat,"")
str=string.rep("0",8-#str%8)..str
comp={}
for i=0,(#str/8) do
table.insert(comp,bits.new(str:sub(i*8+1,i*8+8)):toSbytes())
end
return table.concat(comp,"")
end
function bin.decompress(comp,n)
n=n or 9
local tab={}
for i=1,#comp do
table.insert(tab,bits.new(comp:sub(i,i)).data)
end
tab=table.concat(tab,"")
tab=tab:match("0*(%d+)")
tab=string.rep("0",n-#tab%n)..tab
uncomp={}
for i=0,(#tab/n) do
table.insert(uncomp,tonumber(tab:sub(i*n+1,i*n+n),2))
end
return lzw.decode(uncomp)
end
function bin:getSize()
return self:getlength()
end
function bin.getVersion()
return bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3]
end
function bin:gsub(...)
self.data=self.data:gsub(...)
end
--
function bin:trim()
self.data=self.data:match'^()%s*$' and '' or self.data:match'^%s*(.*%S)'
end
function bin._trim(str)
return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)'
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.data = table.concat(t,"\n")
end
function bin:lines()
local t = {}
local function helper(line) table.insert(t, line) return '' end
helper((self.data: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:find(...)
return self.data:find(...)
end
function bin.fromhex(str)
return (str:gsub('..', function (cc)
return string.char(tonumber(cc, 16))
end))
end
-- working lua base64 codec (c) 2006-2008 by Alex Kloss
-- compatible with lua 5.1
-- http://www.it-rfc.de
-- licensed under the terms of the LGPL2
bin.base64chars = {[0]='A',[1]='B',[2]='C',[3]='D',[4]='E',[5]='F',[6]='G',[7]='H',[8]='I',[9]='J',[10]='K',[11]='L',[12]='M',[13]='N',[14]='O',[15]='P',[16]='Q',[17]='R',[18]='S',[19]='T',[20]='U',[21]='V',[22]='W',[23]='X',[24]='Y',[25]='Z',[26]='a',[27]='b',[28]='c',[29]='d',[30]='e',[31]='f',[32]='g',[33]='h',[34]='i',[35]='j',[36]='k',[37]='l',[38]='m',[39]='n',[40]='o',[41]='p',[42]='q',[43]='r',[44]='s',[45]='t',[46]='u',[47]='v',[48]='w',[49]='x',[50]='y',[51]='z',[52]='0',[53]='1',[54]='2',[55]='3',[56]='4',[57]='5',[58]='6',[59]='7',[60]='8',[61]='9',[62]='-',[63]='_'}
function bin.tob64(data)
local bytes = {}
local result = ""
for spos=0,string.len(data)-1,3 do
for byte=1,3 do bytes[byte] = string.byte(string.sub(data,(spos+byte))) or 0 end
result = string.format('%s%s%s%s%s',result,bin.base64chars[bits.rsh(bytes[1],2)],bin.base64chars[bits.lor(bits.lsh((bytes[1] % 4),4), bits.rsh(bytes[2],4))] or "=",((#data-spos) > 1) and bin.base64chars[bits.lor(bits.lsh(bytes[2] % 16,2), bits.rsh(bytes[3],6))] or "=",((#data-spos) > 2) and bin.base64chars[(bytes[3] % 64)] or "=")
end
return result
end
bin.base64bytes = {['A']=0,['B']=1,['C']=2,['D']=3,['E']=4,['F']=5,['G']=6,['H']=7,['I']=8,['J']=9,['K']=10,['L']=11,['M']=12,['N']=13,['O']=14,['P']=15,['Q']=16,['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,['Y']=24,['Z']=25,['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,['g']=32,['h']=33,['i']=34,['j']=35,['k']=36,['l']=37,['m']=38,['n']=39,['o']=40,['p']=41,['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,['w']=48,['x']=49,['y']=50,['z']=51,['0']=52,['1']=53,['2']=54,['3']=55,['4']=56,['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,['-']=62,['_']=63,['=']=nil}
function bin.fromb64(data)
local chars = {}
local result=""
for dpos=0,string.len(data)-1,4 do
for char=1,4 do chars[char] = bin.base64bytes[(string.sub(data,(dpos+char),(dpos+char)) or "=")] end
result = string.format('%s%s%s%s',result,string.char(bits.lor(bits.lsh(chars[1],2), bits.rsh(chars[2],4))),(chars[3] ~= nil) and string.char(bits.lor(bits.lsh(chars[2],4), bits.rsh(chars[3],2))) or "",(chars[4] ~= nil) and string.char(bits.lor(bits.lsh(chars[3],6) % 192, (chars[4]))) or "")
end
return result
end
-- ^^
function bin:getB64()
return bin.tob64(self.data)
end
if table.unpack==nil then
table.unpack=unpack
end
function bin.tohex(str)
return (str:gsub('.', function (c)
return string.format('%02X', string.byte(c))
end))
end
function bin:streamData(a,b)
if type(a)=='table' then
a,b,t=table.unpack(a)
end
if type(a)=='number' and type(b)=='string' then
return bin.load(self.file,a,b),bin.load(self.file,a,b).data
else
error('Invalid args!!! Is do you have a valid stream handle or is this a streamable object?')
end
end
function bin.new(data,hex,b64)
data=data or ""
data=tostring(data)
local c = {}
setmetatable(c, bin)
if string.sub(data,1,2)=='0x' and hex then
data=string.sub(data,3)
data=bin.fromhex(data)
elseif hex then
data=bin.fromhex(data)
end
if b64 then
data=bin.fromb64(data)
end
c.data=data
c.t='bin'
c.Stream=false
return c
end
function bin.freshStream(file)
bin.new():tofile(file)
return bin.stream(file,false)
end
function bin.stream(file,l)
local c=bin.new()
if bin.streams[file]~=nil then
c.file=file
c.lock = l
c.workingfile=bin.streams[file].workingfile
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
return c
end
function bin:streamwrite(d,n)
if self:canStreamWrite() then
if n then
self.workingfile:seek('set',n)
else
self.workingfile:seek('set',self.workingfile:seek('end'))
end
self.workingfile:write(d)
end
end
function bin:streamread(a,b)
a=a-1
local loc=self.workingfile:seek('cur')
self.workingfile:seek('set',a)
local dat=self.workingfile:read(b-a)
self.workingfile:seek('set',loc)
return dat
end
function bin:streamreadNext(a)
return self.workingfile:read(a)
end
function bin:close()
if self:canStreamWrite() then
self.workingfile:close()
end
end
function bin:flush()
if self:canStreamWrite() then
self.workingfile:flush()
else
self:tofile(self.filepath)
end
end
function bin:open()
if self:canStreamWrite() then
self.workingfile=io.open(self.file,'r+')
end
end
function bin:canStreamWrite()
return (self.Stream==true and self.lock==false)
end
function bin:getDataBuffer(a,b,filler)
if self:canStreamWrite() then
if not(a) and not(b) then
a=1
b=math.huge
elseif a and not(b) then
b=a
a=1
if self:getSize()<a then
stt="\0"
if filler then
stt=filler:sub(1,1)
end
self:streamwrite(string.rep(stt,b-1),1)
end
elseif self:getSize()<b then
stt="\0"
if filler then
stt=filler:sub(1,1)
end
self:streamwrite(string.rep(stt,b-a),a)
end
local me=self
local s=b-a
local ss=a
local max=b
local c={}
local mt={
__index=function(t,k,v) -- GOOD
if k<=s then
return string.byte(me:streamread(k+(ss-1),k+(ss-1)))
else
return
end
end,
__newindex=function(t,k,v) -- GOOD
k=k-1
if type(v)=="number" and s>=k then
me:streamwrite(string.char(v),k+(ss-1))
elseif type(v)=="string" and s>=k then
if #v~=1 then
t:fillBuffer(v,k+(ss))
elseif s>=k then
me:streamwrite(v,k+(ss-1))
else
print("Buffer Overflow!")
end
else
print("Warning Attempting to index outside defined range!")
end
end,
__tostring=function(t) -- GOOD
return t:getBuffer()
end
}
c.t="buffer"
c.dataS={}
function c:getBuffer(a,b) -- GOOD
if not(a) and not(b) then
local str={}
for i=ss,max do
table.insert(str,me:streamread(i+(ss-1),i+(ss-1)))
end
return table.concat(str)
else
return me:streamread(a+(ss-1),b+(ss-1))
end
end
function c:getData() -- GOOD
return self:getBuffer()
end
function c:getBufferTable() -- GOOD
local str={}
for i=ss,max do
table.insert(str,me:streamread(i+(ss-1),i+(ss-1)))
end
return str
end
function c:getBufferSize() -- GOOD
return #self:getBuffer()
end
function c:getlength() -- GOOD
return #self:getBuffer()
end
function c:tonumber(a,b) -- GOOD
return bin.new(self:getBuffer(a,b)):tonumber()
end
c.getSize=c.getlength
function c:fillBuffer(sg,a) -- GOOD
for i=#sg+(a-1),a,-1 do
if i<=max then
local ii=(a+#sg)-i
self[ii+(a-1)]=sg:sub(ii,ii)
else
return print("Buffer Overflow!")
end
end
return a,a+#sg-1
end
setmetatable(c,mt)
return c
else
error("Stream not opened for writing!")
end
end
function bin.load(file,s,r)
if not(s) or not(r) then
if type(file)~="string" then return bin.new() end
local f = io.open(file, 'rb')
local content = f:read('*a')
f:close()
return bin.new(content)
end
s=s or 0
r=r or -1
if type(r)=='number' then
r=r+s-1
elseif type(r)=='string' then
r=tonumber(r) or -1
end
local f = io.open(file, 'rb')
f:seek('set',s)
local content = f:read((r+1)-s)
f:close()
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
io.mkFile(filename,self.data)
end
function bin.trimNul(s)
for i=1,#s do
if s:sub(i,i)=='\0' then
return s:sub(1,i-1)
end
end
return s
end
function bin:match(pat)
return self.data:match(pat)
end
function bin:gmatch(pat)
return self.data:gmatch(pat)
end
function bin:getHash(n)
if self:getlength()==0 then
return "NaN"
end
n=(n or 32)/2
local rand = randomGen:newND(1,self:getlength(),self:getlength())
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:getRandomHash(n)
if self:getlength()==0 then
return "NaN"
end
n=(n or 32)/2
local rand = randomGen:new(math.random(1,self:getlength()^2))
local h,g={},0
for i=1,n do
g=rand:randomInt(1,self:getlength())
table.insert(h,bin.tohex(self:sub(g,g)))
end
return table.concat(h,'')
end
function bin:newDataBuffer(s,def)
local c={}
local mt={
__index=function(t,k,v)
if k<=t.maxBuffer then
if t.dataS[k] then
return string.byte(t.dataS[k])
else
return "NOINDEX"
end
else
return
end
end,
__newindex=function(t,k,v)
if type(v)=="number" and t.maxBuffer>=k then
t.dataS[k]=string.char(v)
elseif type(v)=="string" and t.maxBuffer>=k then
if #v~=1 then
t:fillBuffer(v,k)
elseif t.maxBuffer>=k then
t.dataS[k]=v
else
print("Buffer Overflow!")
end
end
end,
__tostring=function(t)
return t:getBuffer()
end
}
c.t="buffer"
c.dataS={}
if s then
if type(s)=="number" then
c.maxBuffer=s
s=string.rep(def or"\0",s)
else
c.maxBuffer=math.huge
end
for i=1,#s do
c.dataS[i]=s:sub(i,i)
end
else
c.maxBuffer=math.huge
end
function c:getBuffer(a,b)
if a and b then
return table.concat(self.dataS,""):sub(a,b)
else
return table.concat(self.dataS,"")
end
end
function c:getData()
return table.concat(self.dataS,"")
end
function c:getBufferTable()
return self.dataS
end
function c:getBufferSize()
if self.maxBuffer~=math.huge then
return self.maxBuffer
end
return #self:getBuffer()
end
function c:getlength()
return #self:getBuffer(a,b)
end
function c:tonumber(a,b)
return bin.new(self:getBuffer(a,b)):tonumber()
end
c.getSize=c.getlength
function c:fillBuffer(s,a)
for i=0,#s-1 do
if i+a<=self.maxBuffer then
c.dataS[i+a]=s:sub(i+1,i+1)
else
return "Buffer Overflow!"
end
end
return a,a+#s-1
end
setmetatable(c,mt)
return c
end
function bin:getHash2(h,n)
n=n or 1024
h=(h or 32)
local temp=bin.new()
local len=self:getSize()
local seg=math.ceil(len/n)
temp:fill("\0",h)
for i=1,seg do
local s=bin.new(self:sub(n*(i-1)+1,n*i)):getHash(h)
for i=1,h do
temp:shiftbit(string.byte(s:sub(i,i)),i)
end
end
return temp:getHEX()
end
function bin.encryptA(data,seed)
seed=seed or 1
local d=bin.new(data)
local r=randomGen:newND(1,#d.data,seed)
for i=1,#d.data do
d:shiftbit(r:nextInt(),i)
end
return bin.tohex(d.data)
end
function bin.decryptA(data,seed)
seed=seed or 1
local d=bin.new('0x'..data)
local r=randomGen:newND(1,#d.data,seed)
for i=1,#d.data do
d:shiftbit(-r:nextInt(),i)
end
return d.data
end
function bin.encryptB(data,seed)
seed=seed or 'abcdefghijklmnopqrstuvwxyz'
seed=tostring(seed)
local d=bin.new(data)
local r,mr=1,#seed
for i=1,#d.data do
d:shiftbit(string.byte(seed:sub(r,r)),i)
r=r+1
if r>mr then
r=1
end
end
return bin.tohex(d.data)
end
function bin.decryptB(data,seed)
seed=seed or 'abcdefghijklmnopqrstuvwxyz'
seed=tostring(seed)
local d=bin.new('0x'..data)
local r,mr=1,#seed
for i=1,#d.data do
d:shiftbit(-string.byte(seed:sub(r,r)),i)
r=r+1
if r>mr then
r=1
end
end
return d.data
end
function bin:encrypt(seed)
seed=seed or 'abcdefghijklmnopqrstuvwxyz'
seed=tostring(seed)
local r,mr=1,#seed
for i=1,self:getlength() do
self:shiftbit(string.byte(seed:sub(r,r)),i)
r=r+1
if r>mr then
r=1
end
end
end
function bin:decrypt(seed)
seed=seed or 'abcdefghijklmnopqrstuvwxyz'
seed=tostring(seed)
local r,mr=1,#seed
for i=1,self:getlength() do
self:shiftbit(-string.byte(seed:sub(r,r)),i)
r=r+1
if r>mr then
r=1
end
end
end
function bin.randomName(n,ext)
n=n or math.random(7,15)
if ext then
a,b=ext:find('.',1,true)
if a and b then
ext=ext:sub(2)
end
end
local str,h = '',0
strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
for i=1,n do
h = math.random(1,#strings)
str = str..''..strings[h]
end
return str..'.'..(ext or 'tmp')
end
function bin.newTempFile(data)
data=data or ''
local name=bin.randomName()
bin.new():tofile(name)
local tempfile=bin.stream(name,false)
tempfile:streamwrite(data,0)
tempfile:setEndOfFile(#data)
return tempfile
end
function bin:wipe()
if self:canStreamWrite() then
self:close()
os.remove(self.file)
self:open()
else
self.data=''
end
end
function bin:setEndOfFile(n)
if self:canStreamWrite() then
local name=bin.randomName()
local tempfile=bin.stream(name,false)
tempfile:streamwrite(self:sub(0,n-1))
self:close()
os.remove(self.file)
tempfile:close()
os.rename(name,self.file)
self:open()
tempfile=nil
else
self.data=self.data:sub(1,n)
end
end
function bin:reverse()
if self:canStreamWrite() then
local x,f,b=self:getlength(),0,0
for i=0,math.floor((x-1)/2) do
self:streamwrite(self:sub(i+1,i+1),x-i-1)
self:streamwrite(self:sub(x-i,x-i),i)
end
elseif self.Stream==false then
self.data=string.reverse(self.data)
end
end
function bin:flipbits()
if self:canStreamWrite() then
for i=0,self:getlength()-1 do
self:streamwrite(string.char(255-string.byte(self:streamread(i,i))),i)
end
elseif self.Stream==false then
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:flipbit(i)
if self:canStreamWrite() then
self:streamwrite(string.char(255-string.byte(self:streamread(i-1,i-1))),i-1)
elseif self.Stream==false then
self:mutate(string.char(255-string.byte(string.sub(self.data,i,i))),i)
end
end
function bin:segment(a,b) -- needs to be updated!!!
if self:canStreamWrite() then
--[[local pos=1
for i=a,b do
self:streamwrite(self:sub(i,i),b-a-i)
end]]
local temp=self:sub(a,b)
self:close()
local f=io.open(self.file,'w')
f:write(temp)
io.close(f)
self:open()
elseif self.Stream==false then
self.data=string.sub(self.data,a,b)
end
end
function bin:insert(i,a)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
if type(i)=='number' then i=string.char(i) end
self.data=string.sub(self.data,1,a)..i..string.sub(self.data,a+1)
end
end
function bin:parseN(n)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
local temp={}
for i=1,#self.data do
if i%n==0 then
table.insert(temp,string.sub(self.data,i,i))
end
end
self.data=table.concat(temp,'')
end
end
function bin:parse(n,f)
local f = f
local n=n or 1
if not(f) then return end
for i=1,self:getlength() do
if i%n==0 then
f(i,self,self:sub(i,i))
end
end
end
function bin.copy(file,tofile,s)
if not(s) then
bin.load(file):tofile(tofile)
else
rf=bin.stream(file)
wf=bin.stream(tofile,false)
for i=1,rf:getlength(),s do
wf:streamwrite(rf:sub(i,i-1+s))
end
end
end
function bin:getlength()
if self.Stream then
if self.workingfile==nil then print("Error getting size of file!") return 0 end
local current = self.workingfile:seek() -- get current position
local size = self.workingfile:seek('end') -- get file size
self.workingfile:seek('set', current) -- restore position
return size
elseif self.Stream==false then
return #self.data
end
end
function bin:sub(a,b)
if self.Stream then
return bin.load(self.file,a-1,tostring(b-1)).data
elseif self.Stream==false then
return string.sub(self.data,a,b)
end
end
function bin:tackB(d)
if self:canStreamWrite() then
-- do something don't know if possible
elseif self.Stream==false then
self.data=d..self.data
end
end
function bin:tackE(d)
if type(d)=='table' then
if d:canStreamWrite() then
d=d:sub(1,d:getlength())
else
d=d.data
end
return
end
if self:canStreamWrite() then
self:streamwrite(d)
elseif self.Stream==false then
self.data=self.data..d
end
end
function bin:clone(filename)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
return bin.new(self.data)
end
end
function bin.closeto(a,b,v)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
if type(a)~=type(b) then
error('Attempt to compare unlike types')
elseif type(a)=='number' and type(b)=='number' then
return math.abs(a-b)<=v
elseif type(a)=='table' and type(b)=='table' then
if a.data and b.data then
return (math.abs(string.byte(a.data)-string.byte(b.data)))<=v
else
error('Attempt to compare non-bin data')
end
elseif type(a)=='string' and type(b)=='string' then
return math.abs(string.byte(a)-string.byte(b))<=v
else
error('Attempt to compare non-bin data')
end
end
end
function bin:compare(_bin,t)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
t=t or 1
local tab={}
local a,b=self:getlength(),_bin:getlength()
if not(a==b) then
print('Unequal Lengths!!! Equalizing...')
if a>b then
_bin.data=_bin.data..string.rep(string.char(0),a-b)
else
self.data=self.data..string.rep(string.char(0),b-a)
end
end
if t==1 then
for i=1,self:getlength() do
table.insert(tab,self:sub(i,i)==_bin:sub(i,i))
end
else
for i=1,self:getlength() do
table.insert(tab,bin.closeto(self:sub(i,i),_bin:sub(i,i),t))
end
end
local temp=0
for i=1,#tab do
if tab[i]==true then
temp=temp+1
end
end
return (temp/#tab)*100
end
end
function bin:shift(n)
if self:canStreamWrite() then
local a,b,x,p='','',self:getlength(),0
for i=1,x do
if i+n>x then
p=(i+n)-(x)
else
p=i+n
end
end
elseif self.Stream==false then
n=n or 0
local s=#self.data
if n>0 then
self.data = string.sub(self.data,s-n+1)..string.sub(self.data,1,s-n)
elseif n<0 then
n=math.abs(n)
self.data = string.sub(self.data,n+1)..string.sub(self.data,1,n*1)
end
end
end
function bin:delete(a,b)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
if type(a)=='string' then
local tab={}
for i=1,self:getlength() do
if self:getbyte(i)~=string.byte(a) then
table.insert(tab,self:sub(i,i))
end
end
self.data=table.concat(tab)
elseif a and not(b) then
self.data=self:sub(1,a-1)..self:sub(a+1)
elseif a and b then
self.data=self:sub(1,a-1)..self:sub(b+1)
else
self.data=''
end
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:getbyte(n)
return string.byte(self:sub(n,n))
end
function bin:shuffle(s)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
s=tonumber(s) or 4546
math.randomseed(s)
local t={}
for i=1,self:getlength() do
table.insert(t,self:sub(i,i))
end
local n = #t
while n >= 2 do
local k = math.random(n)
t[n], t[k] = t[k], t[n]
n = n - 1
end
self.data=table.concat(t)
end
end
function bin:tobits(i)
return bits.new(self:getbyte(i))
end
function bin:mutate(a,i)
if self:canStreamWrite() then
self:streamwrite(a,i-1)
elseif self.Stream==false then
self:delete(i)
self:insert(a,i-1)
end
end
function bin:parseA(n,a,t)
if self:canStreamWrite() then
-- do something
elseif self.Stream==false then
local temp={}
for i=1,#self.data do
if i%n==0 then
if t then
table.insert(temp,a)
table.insert(temp,string.sub(self.data,i,i))
else
table.insert(temp,string.sub(self.data,i,i))
table.insert(temp,a)
end
else
table.insert(temp,string.sub(self.data,i,i))
end
end
self.data=table.concat(temp,'')
end
end
function bin:merge(o,t)
if self:canStreamWrite() then
self:close()
self.workingfile=io.open(self.file,'a+')
self.workingfile:write(o.data)
self:close()
self:open()
elseif self.Stream==false then
if not(t) then
self.data=self.data..o.data
else
seld.data=o.data..self.data
end
end
end
function bin:cryptM()
self:flipbits()
self:reverse()
end
function bin.escapeStr(str)
local temp=''
for i=1,#str do
temp=temp..'\\'..string.byte(string.sub(str,i,i))
end
return temp
end
function bin.ToStr(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
depth = depth or 0
local tmp = string.rep(" ", depth)
if name then
if type(name) == "string" then
tmp = tmp .. "[\""..name.."\"] = "
else
tmp = tmp .. "["..(name or "").."] = "
end
end
if type(val) == "table" then
tmp = tmp .. "{" .. (not skipnewlines and " " or "")
for k, v in pairs(val) do
tmp = tmp .. bin.ToStr(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and " " or "")
end
tmp = tmp .. string.rep(" ", depth) .. "}"
elseif type(val) == "number" then
tmp = tmp .. tostring(val)
elseif type(val) == "string" then
tmp = tmp .. string.format("%q", val)
elseif type(val) == "boolean" then
tmp = tmp .. (val and "true" or "false")
else
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
end
return tmp
end
function bin:addBlock(d,n,e)
local temp={}
if type(d)=='table' then
if d.t=='bin' then
temp=d
elseif d.t=='bit' then
temp=bin.new(d:tobytes())
else
self:addBlock('return '..bin.ToStr(d))
return
end
elseif type(d)=='string' then
temp=bin.new(d)
if e or not(n) then
temp.data=temp.data..'_EOF'
temp:flipbits()
end
elseif type(d)=='function' then
temp=bin.new(string.dump(d))
if e or not(n) then
temp.data=temp.data..'_EOF'
temp:flipbits()
end
elseif type(d)=='number' then
local nn=tostring(d)
if nn:find('.',1,true) then
temp=bin.new(nn)
temp.data=temp.data..'_EOF'
temp:flipbits()
else
temp=bits.new(d):tobytes()
if not n then
temp.data=temp.data..'_EOF'
temp:flipbits()
end
end
elseif type(d)=='boolean' then
n=1
if d then
temp=bits.new(math.random(0,127)):tobytes()
else
temp=bits.new(math.random(128,255)):tobytes()
end
end
if n then
if temp:getlength()<n then
temp:merge(bin.new(string.rep(string.char(0),n-temp:getlength())))
elseif temp:getlength()>n then
temp:segment(1,n)
end
end
self:merge(temp)
end
function bin:getBlock(t,n,se)
if not(self.Block) then
self.Block=1
end
local x=self.Block
local temp=bin.new()
if n then
temp=bin.new(self:sub(x,x+n-1))
self.Block=self.Block+n
end
if se then
self.Block=self.Block+se
end
if t=='stringe' or t=='stre' or t=='se' and n then
temp:flipbits()
bin.lastBlockSize=#temp
return temp.data
elseif t=='string' or t=='str' or t=='s' and n then
bin.lastBlockSize=#temp
return temp.data
elseif t=='number' or t=='num' or t=='n' and n then
bin.lastBlockSize=n
return self:tonumber(x,x+n-1)
elseif t=='boolean' or t=='bool' or t=='b' then
self.Block=self.Block+1
bin.lastBlockSize=1
return self:tonumber(x,x)<127
elseif t=='stringe' or t=='stre' or t=='se' or t=='string' or t=='str' or t=='s' then
local a,b=self:scan('_EOF',self.Block,true)
if not(b) then return nil end
local t=bin.new(self:sub(self.Block,b-4))
bin.lastBlockSize=t:getlength()
t:flipbits()
self.Block=self.Block+t:getlength()+4
return tostring(t)
elseif t=='table' or t=='tab' or t=='t' then
temp=self:getBlock('s')
bin.lastBlockSize=#temp
return assert(loadstring(temp))()
elseif t=='function' or t=='func' or t=='f' then
local temp=self:getBlock('s')
bin.lastBlockSize=#temp
return assert(loadstring(temp))
elseif t=='number' or t=='num' or t=='n' then
local num=bin.new(self:getBlock('s'))
bin.lastBlockSize=#num
if tonumber(num.data) then
return tonumber(num.data)
end
local a,b=num:tonumber()
return a
elseif n then
-- C data
else
print('Invalid Args!!!')
end
end
function bin:seek(n)
self.Block=self.Block+n
end
function bin.NumtoHEX(num)
local hexstr = '0123456789ABCDEF'
local s = ''
while num > 0 do
local mod = math.fmod(num, 16)
s = string.sub(hexstr, mod+1, mod+1) .. s
num = math.floor(num / 16)
end
if s == '' then
s = '0'
end
return s
end
function bin:getHEX(a,b,e)
a=a or 1
local temp = self:sub(a,b)
if e then temp=string.reverse(temp) end
return bin.tohex(temp)
end
function bin.HEXtoBin(hex,e)
if e then
return bin.new(string.reverse(bin.fromhex(hex)))
else
return bin.new(bin.fromhex(hex))
end
end
function bin.HEXtoStr(hex,e)
if e then
return string.reverse(bin.fromhex(hex))
else
return bin.fromhex(hex)
end
end
function bin:morph(a,b,d)
if self:canStreamWrite() then
local len=self:getlength()
local temp=bin.newTempFile(self:sub(b+1,self:getlength()))
self:streamwrite(d,a-1)
print(temp:sub(1,temp:getlength()))
self:setEndOfFile(len+(b-a)+#d)
self:streamwrite(temp:sub(1,temp:getlength()),a-1)
temp:remove()
elseif self.Stream==false then
if a and b then
self.data=self:sub(1,a-1)..d..self:sub(b+1)
else
print('error both arguments must be numbers and the third a string')
end
end
end
function bin.endianflop(data)
return string.reverse(data)
end
function bin:scan(s,n,f)
n=n or 1
if self.Stream then
for i=n,self:getlength() do
if f then
local temp=bin.new(self:sub(i,i+#s-1))
temp:flipbits()
if temp.data==s then
return i,i+#s-1
end
else
if self:sub(i,i+#s-1)==s then
return i,i+#s-1
end
end
end
elseif self.Stream==false then
if f then
s=bin.new(s)
s:flipbits()
s=s.data
end
n=n or 1
local a,b=string.find(self.data,s,n,true)
return a,b
end
end
function bin:fill(s,n)
if self:canStreamWrite() then
self:streamwrite(string.rep(s,n),0)
self:setEndOfFile(n*#s)
elseif self.Stream==false then
self.data=string.rep(s,n)
end
end
function bin:fillrandom(n)
if self:canStreamWrite() then
local t={}
for i=1,n do
table.insert(t,string.char(math.random(0,255)))
end
self:streamwrite(table.concat(t),0)
self:setEndOfFile(n)
elseif self.Stream==false then
local t={}
for i=1,n do
table.insert(t,string.char(math.random(0,255)))
end
self.data=table.concat(t)
end
end
function bin.packLLIB(name,tab,ext)
local temp=bin.new()
temp:addBlock('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>')
temp:addBlock(bin.getVersion())
temp:addBlock(tab)
for i=1,#tab do
temp:addBlock(tab[i])
temp:addBlock(bin.load(tab[i]).data)
end
temp:addBlock('Done')
temp:tofile(name.. ('.'..ext or '.llib'))
end
function bin.unpackLLIB(name,exe,todir,over,ext)
local temp=bin.load(name..('.'..ext or '.llib'))
local name=''
Head=temp:getBlock('s')
ver=temp:getBlock('s')
infiles=temp:getBlock('t')
if ver~=bin.getVersion() then
print('Incompatable llib file')
return nil
end
local tab={}
while name~='Done' do
name,data=temp:getBlock('s'),bin.new(temp:getBlock('s'))
if string.find(name,'.lua',1,true) then
table.insert(tab,data.data)
else
if not(bin.fileExist((todir or '')..name) and not(over)) then
data:tofile((todir or '')..name)
end
end
end
os.remove((todir or '')..'Done')
if exe then
for i=1,#tab do
assert(loadstring(tab[i]))()
end
end
return infiles
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:shiftbits(n)
if self:canStreamWrite() then
n=n or 0
if n>=0 then
for i=0,self:getlength() do
print(string.byte(self:sub(i,i))+n%256)
self:streamwrite(string.char(string.byte(self:sub(i,i))+n%256),i-1)
end
else
n=math.abs(n)
for i=0,self:getlength() do
self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i-1)
end
end
elseif self.Stream==false then
n=n or 0
if n>=0 then
for i=1,self:getlength() do
self:morph(i,i,string.char(string.byte(self:sub(i,i))+n%256))
end
else
n=math.abs(n)
for i=1,self:getlength() do
self:morph(i,i,string.char((string.byte(self:sub(i,i))+(256-n%256))%256))
end
end
end
end
function bin:shiftbit(n,i)
if self:canStreamWrite() then
i=i-1
n=n or 0
if n>=0 then
print((string.byte(self:sub(i,i))+n)%256,n)
self:streamwrite(string.char((string.byte(self:sub(i,i))+n)%256),i-1)
else
n=math.abs(n)
print((string.byte(self:sub(i,i))+(256-n))%256,n)
self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i-1)
end
elseif self.Stream==false then
n=n or 0
if n>=0 then
self:morph(i,i,string.char((string.byte(self:sub(i,i))+n)%256))
else
n=math.abs(n)
self:morph(i,i,string.char((string.byte(self:sub(i,i))+(256-n%256))%256))
end
end
end
function bin.decodeBits(par)
if type(par)=='table' then
if par.t=='bit' then
return bin.new(par:toSbytes())
end
else
if par:find(' ') then
par=par:gsub(' ','')
end
local temp=bits.new()
temp.data=par
return bin.new((temp:toSbytes()):reverse())
end
end
function bin.textToBinary(txt)
return bin.new(bits.new(txt:reverse()):getBin())
end
function bin:getData()
if self.Stream then
return self:sub(1,self:getSize())
else
return self.data
end
end
function bin.getLuaVersion()
if type(jit)=="table" then
if jit.version then
return "JIT",jit.version
end
end
return "PUC",_VERSION:match("(%d-)%.(%d+)")
end
function bin.binToBuffer(b)
return bin:newDataBuffer(b.data)
end
function bin.bufferToBin(b)
return bin.new(b:getBuffer())
end
function bin.newNamedBlock(indexSize)
local c={}
c.data=bin.new()
c.lastLoc=0
if indexSize then
indexSize=indexSize+4
end
c.index=bin:newDataBuffer(indexSize)
c.conv={
["n"]="\1",
["b"]="\2",
["s"]="\3",
["t"]="\4",
["f"]="\5"
}
if indexSize then
c.index:fillBuffer(bits.numToBytes(indexSize,4),1)
c.lastLoc=4
else
--c.index:fillBuffer(bits.numToBytes(2048,4),1)
end
function c:tofile(path)
bin.new(self:tostring()):tofile(path)
end
function c:tostring()
c.index:fillBuffer(bits.numToBytes(c.index:getSize()-4,4),1)
return self.index:getBuffer()..self.data.data
end
function c:setPointer(name,data,t)
t=c.conv[t]
data=t..data
local dSize=#data
local index=bin:newDataBuffer()
local nLen=#name
local test=""
index:fillBuffer(bits.numToBytes(self.data:getSize()+1,4),1)
index:fillBuffer(name,5)
self.data:tackE(data)
test=self.index:fillBuffer(index:getBuffer().."\31",self.lastLoc+1)
self.lastLoc=self.lastLoc+1+index:getBufferSize()
if test=="Buffer Overflow!" then
error("Increase Index size!")
end
end
function c:addNamedBlock(name,value)
local bSize=#name
local ftype={}
if type(value)=="number" then
local dat=bits.numToBytes(value,8) -- makes 64 bit version of lua compatable
self:setPointer(name,dat,"n")
elseif type(value)=="boolean" then
if value then
self:setPointer(name,"1","b")
else
self:setPointer(name,"0","b")
end
elseif type(value)=="string" then
self:setPointer(name,value,"s")
elseif type(value)=="table" then
local str=bin.ToStr(value)
self:setPointer(name,str,"t")
elseif type(value)=="function" then
local ver,verM,verm=bin.getLuaVersion()
local data=string.dump(value)
if ver=="JIT" then
ftype=bin:newDataBuffer(bits.numToBytes(0,4)) -- luajit version
else
ftype=bin:newDataBuffer(bits.numToBytes(tonumber(verM..verm),4)) -- lua version with MajorMinor data
end
local fdata=bin.new()
fdata:tackE(ftype:getBuffer()..data)
self:setPointer(name,fdata.data,"f")
elseif type(value)=="userdata" then
error("Userdata cannot be put into a block!")
end
end
if not indexSize then
c:addNamedBlock("__UNBOUNDEDINDEX__",true)
end
return c
end
function bin.newStreamedNamedBlock(indexSize,path,update)
local c={}
c.data=bin.stream(path,false)
c.lastLoc=4
c.conv={
["n"]="\1",
["b"]="\2",
["s"]="\3",
["t"]="\4",
["f"]="\5"
}
if not update then
c.data:tackE(bin:newDataBuffer(indexSize+4 or 2052):getBuffer())
if indexSize then
c.data:mutate(bits.numToBytes(indexSize,4),1)
else
c.data:mutate(bits.numToBytes(2048,4),1)
end
c.indexSize=indexSize+4 or 2052
else
c.indexSize=c.data:tonumber(1,4)
local i=bin.new(c.data:sub(5,c.indexSize+4)).data
local last=0
for b=#i,1,-1 do
if i:sub(b,b)=="\31" then
last=b+4
break
end
end
c.lastLoc=last
end
function c:tofile(path)
--No need when using a streamed block
end
function c:tostring()
return self.index:getBuffer()..self.data.data
end
function c:setPointer(name,data,t)
t=c.conv[t]
data=t..data
local dSize=#data
local index=bin:newDataBuffer()
local nLen=#name
local test=""
index:fillBuffer(bits.numToBytes((self.data:getSize()+1)-self.indexSize,4),1)
index:fillBuffer(name,5)
local test=self.data:mutate(index:getBuffer().."\31",self.lastLoc+1)
self.lastLoc=self.lastLoc+1+index:getBufferSize()
self.data:tackE(data)
if test=="Buffer Overflow!" then
error("Increase Index size!")
end
end
function c:addNamedBlock(name,value)
local bSize=#name
local ftype={}
if type(value)=="number" then
local dat=bits.numToBytes(value,8) -- makes 64 bit version of lua compatable
self:setPointer(name,dat,"n")
elseif type(value)=="boolean" then
if value then
self:setPointer(name,"1","b")
else
self:setPointer(name,"0","b")
end
elseif type(value)=="string" then
self:setPointer(name,value,"s")
elseif type(value)=="table" then
local str=bin.ToStr(value)
self:setPointer(name,str,"t")
elseif type(value)=="function" then
local ver,verM,verm=bin.getLuaVersion()
local data=string.dump(value)
if ver=="JIT" then
ftype=bin:newDataBuffer(bits.numToBytes(0,4)) -- luajit version
else
ftype=bin:newDataBuffer(bits.numToBytes(tonumber(verM..verm),4)) -- lua version with MajorMinor data
end
local fdata=bin.new()
fdata:tackE(ftype:getBuffer()..data)
self:setPointer(name,fdata.data,"f")
elseif type(value)=="userdata" then
error("Userdata cannot be put into a block!")
end
end
function c:close()
self:addNamedBlock("",false)
self.data:close()
end
return c
end
function bin.loadNamedBlock(path)
local c={}
c.data=bin.stream(path)
c.iSize=c.data:tonumber(1,4)
c.index=bin.new(c.data:sub(5,c.iSize+4))
c.sData=bin.new(c.data:sub(c.iSize+5,-1))
function c:CheckRestOfIndex(name)
local a,b=self.index:scan(name)
local d=self.index:tonumber(b+2,b+5)
if d==0 or b+5>self.iSize then
return -1
end
return d
end
function c:getIndexes()
local tab={}
ind=5
while ind do
local a=self.index:find("\31",ind)
if not a then break end
local b=self.index:sub(ind,a-1)
table.insert(tab,b)
ind=a+5
end
return tab
end
function c:getBlock(name)
local a,b=self.index:scan(name)
if not a then return "index not found" end
local dloc=self.index:tonumber(a-4,a-1)
local dindex=bin:newDataBuffer(self.sData:sub(dloc,dloc))
if dindex[1]==0x01 then -- type number
return self.sData:tonumber(dloc+1,dloc+8)
elseif dindex[1]==0x02 then -- type bool
return ({[1]=true,[0]=false})[tonumber(self.sData:sub(dloc+1,dloc+1))]
elseif dindex[1]==0x03 then -- type string
local dend=self:CheckRestOfIndex(name)--self.index:tonumber(b+2,b+5)
return self.sData:sub(dloc+1,dend-1)
elseif dindex[1]==0x04 then -- type table
local dend=self.index:tonumber(b+2,b+5)
return loadstring("return "..self.sData:sub(dloc+1,dend-1))()
elseif dindex[1]==0x05 then -- type function
local dend=self:CheckRestOfIndex(name)--self.index:tonumber(b+2,b+5)
local _ver=self.sData:tonumber(dloc+1,dloc+4)
local ver,verM,verm=bin.getLuaVersion()
if tonumber(verM..verm)==_ver then
return loadstring(self.sData:sub(dloc+5,dend-1))
else
return function() error("This lua function is not compatible with the current version of lua!") end
end
end
end
return c
end
function bin.namedBlockManager(name)
if type(name)=="string" then
local i={}
local data=bin.loadNamedBlock(name)
local mt={
__index=function(t,k)
return data:getBlock(k)
end,
}
setmetatable(i,mt)
return i
else
local i={}
local data=bin.newNamedBlock(name)
local mt={
__newindex=function(t,k,v)
data:addNamedBlock(k,v)
end,
__index=data
}
setmetatable(i,mt)
return i
end
end
function bin.getIndexSize(tab)
size=0
for i=1,#tab do
size=size+#tab[i]+5
end
return size+5
end
function bin.gcd( m, n )
while n ~= 0 do
local q = m
m = n
n = q % n
end
return m
end
function bin.numToFraction(num)
num=num or error("Must enter a number!")
local n=#tostring(num)
num=num*(10^n)
local d=(10^n)
local g=bin.gcd(num,d)
return tostring(num/g).."/"..tostring(d/g),num/g,d/g
end
function bin.doubleToString(double)
local s=({[false]="-",[true]="+"})[double>=0]
double=math.abs(double)
local _,n,d=bin.numToFraction(double)
gfit=4
local a=bits.numToBytes(n,gfit,function(ref)
ref.fit=12 -- should be able to pack any number into that space
ref.num=string.rep("\0",12-#ref.num)..ref.num
if s=="-" then
s="_"
else
s="="
end
gfit=12
end)
local b=bits.numToBytes(d,gfit)
return s..a..b
end
function bin.stringToDouble(str)
local s=str:sub(1,1)
if #str~=9 and #str~=25 then
if s~="-" and s~="+" and s~="_" and s~="=" then
print(s)
error("Not a double encoded string")
end
error("Not a double encoded string")
end
local n,d
if s=="_" or s=="=" then
n,d=str:sub(2,13),str:sub(14)
else
n,d=str:sub(2,5),str:sub(6)
end
local n=bin.new(n):tonumber()
local d=bin.new(d):tonumber()
local num=n/d
if s=="-" or s=="_" then
num=-num
end
return num
end
--[[----------------------------------------
VFS
------------------------------------------]]
local _require = require
function require(path,vfs)
if bin.fileExist(path..'.lvfs') then
local data = bin.loadVFS(path..'.lvfs')
if data:fileExist(vsf) then
loadstring(data:readFile(vfs))()
end
else
return _require(path)
end
end
function bin.loadVFS(path)
local vfs=bin.newVFS()
local temp=bin.stream(path,false)
local files=temp:getBlock("t")
local size=0
for i=1,#files do
local p,len=files[i]:match("(.-)|(.+)")
len=tonumber(len)
size=size+bin.lastBlockSize
local dat=temp:sub(size+5,size+len+4)
bin.lastBlockSize=len
vfs:mkfile(p:gsub("%./",""),dat)
end
return vfs
end
function bin.copyDir(dir,todir)
local vfs=bin.newVFS(dir,true)
vfs:toFS(todir)
vfs=nil
end
function bin.newVFS(t,l)
l=l or true
if type(t)=='string' then
t=io.parseDir(t,l)
end
local c={}
c.FS= t or {}
function c:merge(vfs)
bin.newVFS(table.merge(self.FS,vfs.FS))
end
function c:mirror(file)
self:mkfile(file,file)
end
function c:mkdir(path)
table.merge(self.FS,io.pathToTable(path))
end
function c:scanDir(path)
path=path or ''
local tab={}
if path=='' then
for i,v in pairs(self.FS) do
tab[#tab+1]=i
end
return tab
end
spath=io.splitPath(path)
local last=self.FS
for i=1,#spath-1 do
last=last[spath[i]]
end
return last[spath[#spath]]
end
function c:getFiles(path)
if not self:dirExist(path) then return end
path=path or ''
local tab={}
if path=='' then
for i,v in pairs(self.FS) do
if self:fileExist(i) then
tab[#tab+1]=i
end
end
return tab
end
spath=io.splitPath(path)
local last=self.FS
for i=1,#spath-1 do
last=last[spath[i]]
end
local t=last[spath[#spath]]
for i,v in pairs(t) do
if self:fileExist(path..'/'..i) then
tab[#tab+1]=path..'/'..i
end
end
return tab
end
function c:getDirectories(path)
if not self:dirExist(path) then return end
path=path or ''
local tab={}
if path=='' then
for i,v in pairs(self.FS) do
if self:dirExist(i) then
tab[#tab+1]=i
end
end
return tab
end
spath=io.splitPath(path)
local last=self.FS
for i=1,#spath-1 do
last=last[spath[i]]
end
local t=last[spath[#spath]]
for i,v in pairs(t) do
if self:dirExist(path..'/'..i) then
tab[#tab+1]=path..'/'..i
end
end
return tab
end
function c:mkfile(path,data)
local name=io.getFullName(path)
local temp=path:reverse()
local a,b=temp:find('/')
if not a then
a,b=temp:find('\\')
end
if a then
temp=temp:sub(a+1):reverse()
path=temp
local t,l=io.pathToTable(path)
l[name]=data
table.merge(self.FS,t)
else
self.FS[name]=data
end
end
function c:remove(path)
if path=='' or path==nil then return end
spath=io.splitPath(path)
local last=self.FS
for i=1,#spath-1 do
last=last[spath[i]]
end
last[spath[#spath]]=nil
end
function c:readFile(path)
spath=io.splitPath(path)
local last=self.FS
for i=1,#spath do
last=last[spath[i]]
end
if type(last)=='userdata' then
last=last:read('*all')
end
return last
end
function c:copyFile(p1,p2)
self:mkfile(p2,self:readFile(p1))
end
function c:moveFile(p1,p2)
self:copyFile(p1,p2)
self:remove(p1)
end
function c:fileExist(path)
return type(self:readFile(path))=='string'
end
function c:dirExist(path)
if path=='' or path==nil then return end
spath=io.splitPath(path)
local last=self.FS
for i=1,#spath-1 do
last=last[spath[i]]
end
if last[spath[#spath]]~=nil then
if type(last[spath[#spath]])=='table' then
return true
end
end
return false
end
function c:_getHierarchy()
local ord={}
local datlink=bin.new()
local function toStr(val, name, skipnewlines, depth, path)
skipnewlines = skipnewlines or false
path=path or "."
depth = depth or 0
local tmp = string.rep(" ", depth)
if name then
if type(name) == "string" then
tmp = tmp .. "[\""..name.."\"] = "
else
tmp = tmp .. "["..(name or "").."] = "
end
end
if type(val) == "table" then
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
for k, v in pairs(val) do
tmp = tmp .. toStr(v, k, skipnewlines, depth + 1,path.."/"..k) .. "," .. (not skipnewlines and "\n" or "")
end
tmp = tmp .. string.rep(" ", depth) .. "}"
elseif type(val) == "string" then
tmp = tmp .. #val
datlink:tackE(val)
ord[#ord+1]=path.."|"..#val
end
return tmp
end
return toStr(self.FS),ord,datlink
end
function c:getHierarchy()
local ord={}
local function toStr(val, name, skipnewlines, depth, path)
skipnewlines = skipnewlines or false
path=path or "."
depth = depth or 0
local tmp = string.rep(" ", depth)
if name then
if type(name) == "string" then
tmp = tmp .. "[\""..name.."\"] = "
else
tmp = tmp .. "["..(name or "").."] = "
end
end
if type(val) == "table" then
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
for k, v in pairs(val) do
tmp = tmp .. toStr(v, k, skipnewlines, depth + 1,path.."/"..k) .. "," .. (not skipnewlines and "\n" or "")
end
tmp = tmp .. string.rep(" ", depth) .. "}"
elseif type(val) == "string" then
tmp = tmp .. ";"
ord[#ord+1]=path.."|"..#val
end
return tmp
end
return toStr(self.FS),ord
end
function c:tofile(path)
local temp=bin.new()
local h,o,link=self:_getHierarchy()
temp:addBlock(o)
temp:merge(link)
temp:tofile(path)
end
function c:toFS(path)
if path then
if path:sub(-1,-1)~='\\' then
path=path..'\\'
elseif path:find('/') then
path=path:gsub('/','\\')
end
io.mkDir(path)
else
path=''
end
function build(tbl, indent, folder)
if not indent then indent = 0 end
if not folder then folder = '' end
for k, v in pairs(tbl) do
formatting = string.rep(' ', indent) .. k .. ':'
if type(v) == 'table' then
if v.t~=nil then
io.mkFile(folder..k,tostring(v),'wb')
else
if not(io.dirExists(path..folder..string.sub(formatting,1,-2))) then
io.mkDir(folder..string.sub(formatting,1,-2))
end
build(v,0,folder..string.sub(formatting,1,-2)..'\\')
end
elseif type(v)=='string' then
io.mkFile(folder..k,v,'wb')
elseif type(v)=='userdata' then
io.mkFile(folder..k,v:read('*all'),'wb')
end
end
end
build(self.FS,0,path)
end
function c:print()
table.print(self.FS)
end
return c
end
--[[----------------------------------------
BITS
------------------------------------------]]
function bits.lsh(value,shift)
return (value*(2^shift)) % 256
end
function bits.rsh(value,shift)
return math.floor(value/2^shift) % 256
end
function bits.bit(x,b)
return (x % 2^b - x % 2^(b-1) > 0)
end
function bits.lor(x,y)
result = 0
for p=1,8 do result = result + (((bits.bit(x,p) or bits.bit(y,p)) == true) and 2^(p-1) or 0) end
return result
end
function bits.newBitBuffer(n)
--
end
function bits.newConverter(bitsIn,bitsOut)
local c={}
--
end
bits.ref={}
function bits.newByte(d)
local c={}
if type(d)=="string" then
if #d>1 or #d<1 then
error("A byte must be one character!")
else
c.data=string.byte(d)
end
elseif type(d)=="number" then
if d>255 or d<0 then
error("A byte must be between 0 and 255!")
else
c.data=d
end
else
error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!")
end
c.__index=function(self,k)
if k>=0 and k<9 then
if self.data==0 then
return 0
elseif self.data==255 then
return 1
else
return bits.ref[self.data][k]
end
end
end
c.__tostring=function(self)
return bits.ref[tostring(self.data)]
end
setmetatable(c,c)
return c
end
function bits.newByteArray(s)
local c={}
if type(s)~="string" then
error("Must be a string type or bin/buffer type")
elseif type(s)=="table" then
if s.t=="sink" or s.t=="buffer" or s.t=="bin" then
local data=s:getData()
for i=1,#data do
c[#c+1]=bits.newByte(data:sub(i,i))
end
else
error("Must be a string type or bin/buffer type")
end
else
for i=1,#s do
c[#c+1]=bits.newByte(s:sub(i,i))
end
end
return c
end
function bits.new(n,s)
if type(n)=='string' then
local t=tonumber(n,2)
if t and #n<8 and not(s) then
t=nil
end
if not(t) then
t={}
for i=#n,1,-1 do
table.insert(t,bits:conv(string.byte(n,i)))
end
n=table.concat(t)
else
n=t
end
end
local temp={}
temp.t='bit'
setmetatable(temp, bits)
if type(n)~='string' then
local tab={}
while n>=1 do
table.insert(tab,n%2)
n=math.floor(n/2)
end
local str=string.reverse(table.concat(tab))
if #str%8~=0 then
str=string.rep('0',8-#str%8)..str
end
temp.data=str
else
temp.data=n
end
setmetatable({__tostring=function(self) return self.data end},temp)
return temp
end
for i=0,255 do
local d=bits.new(i).data
bits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")}
bits.ref[tostring(i)]=d
bits.ref[d]=i
bits.ref["\255"..string.char(i)]=d
end
function bits.numToBytes(n,fit,func)
local num=bits.new(n):toSbytes()
num=bin.endianflop(num)
local ref={["num"]=num,["fit"]=fit}
if fit then
if fit<#num then
if func then
print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!")
func(ref)
else
print("Warning: attempting to store a number that takes up more space than allotted!")
end
return ref.num:sub(1,ref.fit)
elseif fit==#num then
return num
else
return string.rep("\0",fit-#num)..num
end
else
return num
end
end
function bits:conv(n)
local tab={}
while n>=1 do
table.insert(tab,n%2)
n=math.floor(n/2)
end
local str=string.reverse(table.concat(tab))
if #str%8~=0 then
str=string.rep('0',8-#str%8)..str
end
return str
end
function bits:add(i)
if type(i)=='number' then
i=bits.new(i)
end
self.data=self:conv(tonumber(self.data,2)+tonumber(i.data,2))
end
function bits:sub(i)
if type(i)=='number' then
i=bits.new(i)
end
self.data=self:conv(tonumber(self.data,2)-tonumber(i.data,2))
end
function bits:multi(i)
if type(i)=='number' then
i=bits.new(i)
end
self.data=self:conv(tonumber(self.data,2)*tonumber(i.data,2))
end
function bits:div(i)
if type(i)=='number' then
i=bits.new(i)
end
self.data=self:conv(tonumber(self.data,2)/tonumber(i.data,2))
end
function bits:tonumber(s)
if type(s)=='string' then
return tonumber(self.data,2)
end
s=s or 1
return tonumber(string.sub(self.data,(8*(s-1))+1,8*s),2) or error('Bounds!')
end
function bits:isover()
return #self.data>8
end
function bits:flipbits()
tab={}
for i=1,#self.data do
if string.sub(self.data,i,i)=='1' then
table.insert(tab,'0')
else
table.insert(tab,'1')
end
end
self.data=table.concat(tab)
end
function bits:tobytes()
local tab={}
for i=self:getbytes(),1,-1 do
table.insert(tab,string.char(self:tonumber(i)))
end
return bin.new(table.concat(tab))
end
function bits:toSbytes()
local tab={}
for i=self:getbytes(),1,-1 do
table.insert(tab,string.char(self:tonumber(i)))
end
return table.concat(tab)
end
function bits:getBin()
return self.data
end
function bits:getbytes()
return #self.data/8
end