--[[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/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()=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: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('') 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