Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- This is eniallator's Compression program that takes an input file and then you can choose to either compress it or decompress it.
- -- The way compression works is by making a table of all the different words that come up in the file.
- -- It will then instead of putting the word in the actual body of the file, it will just put the index of the table that the program has to search for.
- -- The index is in the form of a byte and i use string.char() and string.byte() to convert between the 2.
- --
- -- ================================================================================
- --
- -- Im currently using the following numbers for special cases:
- -- 0 = bigger than 255, 1 = new line, 2 = multiple spaces, 3 = 1 space
- --
- -- I also don't use 13 because when LUA converts character 13 back to it's number, it will be the same result as byte 10.
- -- Aparts from that, every other byte i just use to index the words.
- local tArgs = { ... }
- -- Function to return a table of the lines of a file
- local function fileToLines(file)
- local read = fs.open(file,"r")
- local lines = {}
- -- While loop to keep on adding the current line to a table and if theres no current line, it will break
- while true do
- local currLine = read.readLine()
- if currLine then
- table.insert(lines, currLine)
- else
- break
- end
- end
- read.close()
- return lines
- end
- -- Function to split a string up at it's spaces
- local function wordSplit(string)
- local out = {}
- -- For loop to iterate over the words in the string
- for word in string:gmatch("%S+") do
- table.insert(out, word)
- end
- return out
- end
- -- Function that compression uses, if the number given in the arguments is bigger than 254 it will keep on adding the byte 0 to the return
- local function checkNum(num)
- local out = ""
- -- While to iterate when num is bigger than 254
- while num > 254 do
- out = out .. string.char(0)
- num = num - 254
- end
- -- Making sure num isn't byte 13
- if num >= 13 then num = num + 1 end
- -- Returning the bytes instead of the number.
- return out .. string.char(num)
- end
- -- The compression function
- local function compress(fileName)
- -- Splitting the file into it's lines in a table
- local lines = fileToLines(fileName)
- local outTable = {{}}
- for line=1,#lines do
- local spaces = 0
- local word = ""
- outTable[line+1] = {}
- -- Function to add any new words to the index
- local function sortWord(word)
- if #word > 0 then
- local wordFound = false
- -- Iterating over the first index of outTable
- for i=1,#outTable[1] do
- -- Checking if the word already exists or not
- if outTable[1][i] == word then
- table.insert(outTable[line+1],i+3)
- wordFound = true
- break
- end
- end
- -- Adding the word to the index if it hasn't been found
- if not wordFound then
- table.insert(outTable[1],word)
- table.insert(outTable[line+1],#outTable[1]+3)
- end
- end
- end
- -- Function to handle spaces in the file
- local function sortSpaces(spaces)
- if spaces > 0 then
- -- Checking if the number of spaces is bigger than 1 so it can add a different byte depending on if it is or not
- if spaces > 1 then
- table.insert(outTable[line+1],2)
- table.insert(outTable[line+1],spaces)
- else
- table.insert(outTable[line+1],3)
- end
- end
- end
- local currLine = ""
- -- For to handle the entire compression to convert the file into bytes
- for i=1,#lines[line] do
- local currChar = lines[line]:sub(i,i)
- -- A crude way to split up the lines into words and spaces
- if currChar == " " then
- spaces = spaces + 1
- sortWord(word)
- word = ""
- else
- word = word .. currChar
- sortSpaces(spaces)
- spaces = 0
- end
- end
- sortWord(word)
- sortSpaces(spaces)
- end
- local outString = ""
- -- For loop to combine the outTable into an output string
- for i=1,#outTable do
- for j=1,#outTable[i] do
- if i == 1 then
- if #outString > 0 then outString = outString .. " " end
- outString = outString .. outTable[i][j]
- else
- outString = outString .. checkNum(outTable[i][j])
- end
- end
- -- Adding the new line character to the end of the line. The index is always at line 1 so i choose to add a \n to the end of line 1
- if i == 1 then
- outString = outString .. "\n"
- else
- outString = outString .. string.char(1)
- end
- end
- return outString
- end
- -- The decompression function
- local function decompress(fileName)
- -- Splitting the file into it's lines in a table
- local lines = fileToLines(fileName)
- -- Seperating the index table from the body table
- local index = wordSplit(lines[1])
- local body = {}
- table.remove(lines,1)
- -- For to convert the compressed file into it's original lines and where the indexes should go
- for line=1,#lines do
- -- Inserting the character 10 every time the file goes onto a new line. This is because character 10 actually is the new line character
- if line > 1 then
- table.insert(body,10)
- end
- -- For loop to convert the bytes into the corresponding indexes
- for i=1,#lines[line] do
- local indexNum = string.byte(lines[line]:sub(i))
- if indexNum >= 13 then
- indexNum = indexNum - 1
- end
- table.insert(body,indexNum)
- end
- end
- local counter = 1
- local fullFile = ""
- -- While loop to convert the indexes into the corresponding words (aparts from the special characters)
- while counter < #body do
- -- Checking if the current index is 0 and then converting it into it's actual index (because 0 means it's bigger than 254)
- if body[counter] == 0 then
- local multiples = 0
- -- Adding up the multiples of 254
- while body[counter] == 0 do
- counter = counter + 1
- multiples = multiples + 254
- end
- -- Inserting the corresponding word with the full index from adding the multiples and the current index
- fullFile = fullFile .. index[body[counter] + multiples-3]
- -- Seeing if the current index is 1 which is the new line character
- elseif body[counter] == 1 then
- fullFile = fullFile .. "\n"
- -- Seeing if the current index is 2 and then seeing what the next index is to make that next index * spaces.
- elseif body[counter] == 2 then
- counter = counter + 1
- -- Iterating for the amount of spaces that should be in and adding them
- for i=1,body[counter] do
- fullFile = fullFile .. " "
- end
- -- Seeing if the current index is 3 and inserting a space into the file
- elseif body[counter] == 3 then
- fullFile = fullFile .. " "
- -- If nothing before has caught the index, the corresponding word to that index will be inserted into the file.
- else
- fullFile = fullFile .. index[body[counter]-3]
- end
- counter = counter + 1
- end
- return fullFile
- end
- -- Handling program arguments
- if tArgs[1] == "com" then
- if tArgs[2] and fs.exists(tArgs[2]) then
- if tArgs[3] then
- comString = compress(tArgs[2])
- openFile = assert(fs.open(tArgs[3],"w"),"Something went wrong when trying to open the output file")
- openFile.write(comString)
- openFile.close()
- else
- print("Error: Compression requires a third argument")
- end
- else
- print("Error: Compression requires a valid file name as the second argument.")
- end
- elseif tArgs[1] == "decom" then
- if tArgs[2] and fs.exists(tArgs[2]) and tArgs[3] then
- if tArgs[3] then
- comString = decompress(tArgs[2])
- openFile = assert(fs.open(tArgs[3],"w"),"Something went wrong when trying to open the output file")
- openFile.write(comString)
- openFile.close()
- else
- print("Error: Decompression requires a third argument")
- end
- else
- print("Error: Decompression requires a valid file name as the second argument.")
- end
- else
- print('Error: Invalid syntax. Correct syntax is: "compress [com/decom] [input file name] [output file name]"')
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement