--[[TODO +Add symbols +Better compatiblity with streamables +Add Hash +Add Data Compression +Add Encryption(better) +Create full documentation ]] if not os.getSystemBit then error("The bin library needs the utils library!") end bin={} bin.Version={3,1,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: Everything by me Ryan Ward ]] 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. 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 --WIP vfs = bin.loadVFS(path) -- loads a saved .lvfs file --WIP 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) -- turns hex data into binobj string = bin.HEXtoStr(s) -- 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 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 into a base 10 number so "AXG" in data becomes 4675649 returns left,right parse of data 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 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 numbers are written in Little-endian use bin.endianflop(d) to filp to Big-endian Note: binobj:tonumber() returns little,big so if printing do: l,b=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 *** all changes are made directly to the file no need to do tofile() ]] 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 in 5.1 just use getlength() 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! Notic: 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... ]] bin.data="" bin.t="bin" bin.__index = bin bin.__tostring=function(self) return self.data 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 --[[---------------------------------------- MISC ------------------------------------------]] function log(data,name,fmt) 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 --[[---------------------------------------- BIN ------------------------------------------]] function bin.getVersion() return bin.Version[1].."."..bin.Version[2].."."..bin.Version[3] end --[[function bin:gsub(...) return self.data:gsub(...) end function bin:find(...) return self.data:find(...) end]] function bin:gsub(...) self.data=self.data:gsub(...) end function bin:find(...) self.data=self.data:find(...) end function bin.fromhex(str) return (str:gsub('..', function (cc) return string.char(tonumber(cc, 16)) end)) 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) data=tostring(data) local c = {} setmetatable(c, bin) data=data or "" if string.sub(data,1,2)=="0x" then data=string.sub(data,3) data=bin.fromhex(data) end c.data=data c.t="bin" c.Stream=false return c end function bin.stream(file,l) local c=bin.new() if bin.fileExist(file) then c.file=file c.lock = l c.workingfile=io.open(file,"r+") else c.file=file c.lock = l c.workingfile=io.open(file,"w") io.close(c.workingfile) c.workingfile=io.open(file,"r+") end c.Stream=true 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=tonumber(a) b=tostring(b) return bin.load(self.file,a,b).data end function bin:close() if self:canStreamWrite() then self.workingfile:close() 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.load(file,s,r) if not(s) or not(r) then 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() return bin.new(content) 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.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 os.remove(self.file) 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 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(0,d:getlength()) else d=d.data end 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 l,r end function bin:getbyte(n) return string.byte(self:sub(n,n)) end function bin:encrypt(s) if self:canStreamWrite() then s=tonumber(s) or 4546 math.randomseed(s) self:shift(math.random(1,self:getlength())) self:flipbits() elseif self.Stream==false then s=tonumber(s) or 4546 math.randomseed(s) self:shift(math.random(1,self:getlength())) self:flipbits() end end function bin:decrypt(s) if self:canStreamWrite() then s=tonumber(s) or 4546 math.randomseed(s) self:flipbits() self:shift(-math.random(1,self:getlength())) elseif self.Stream==false then s=tonumber(s) or 4546 math.randomseed(s) self:flipbits() self:shift(-math.random(1,self:getlength())) end 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(t) local dat="{" for i,v in pairs(t) do if type(i)=="number" then i="["..i.."]=" else i="[\""..i.."\"]=" end if type(v)=="string" then dat=dat..i.."[["..v.."]]," elseif type(v)=="number" then dat=dat..i..v.."," elseif type(v)=="boolean" then dat=dat..i..tostring(v).."," elseif type(v)=="table" then dat=dat..i..bin.ToStr(v).."," elseif type(v)=="function" then dat=dat..i.."assert(loadstring(\""..bin.escapeStr(string.dump(v)).."\"))," end end return string.sub(dat,1,-2).."}" 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:segment(1,n) end end self:merge(temp) end function bin:getBlock(t,n) 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 t=="stringe" or t=="stre" or t=="se" and n then temp:flipbits() return temp.data elseif t=="string" or t=="str" or t=="s" and n then return temp.data elseif t=="number" or t=="num" or t=="n" and n then return self:tonumber(x,x+n-1) elseif t=="boolean" or t=="bool" or t=="b" then self.Block=self.Block+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)) 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") if temp=="return }" then return {} end return assert(loadstring(temp))() elseif t=="function" or t=="func" or t=="f" then return assert(loadstring(self:getBlock("s"))) elseif t=="number" or t=="num" or t=="n" then local num=bin.new(self:getBlock("s")) 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,n) n=n or 1 local tab={} for i=1,#data,n do table.insert(tab,1,string.sub(data,i,i+1)) end return table.concat(tab) 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("") 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 self:streamwrite(string.char(string.byte(self:sub(i,i))+n%256),i) else n=math.abs(n) self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i) 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 --[[---------------------------------------- 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) return bin.newVFS(bin.load(path):getBlock("t")) end function bin.copyDir(dir,todir) local vfs=bin.newVFS(dir,true) vfs:toFS(todir) vfs=nil end function bin.newVFS(t,l) 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: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:tofile(path) local temp=bin.new() temp:addBlock(self.FS) 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,v.data,"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.new(n) if type(n)=="string" then local t=tonumber(n,2) 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 not 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 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() print(self.data) return #self.data/8 end