Advertisement
FluttyProger

unzip.lua

Aug 3rd, 2018
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.70 KB | None | 0 0
  1. --[[
  2. ocunzip: unzip zip files in opencomputers
  3. Copyright (c) 2015-16 GreaseMonkey
  4.  
  5. Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. this software and associated documentation files (the "Software"), to deal in
  7. the Software without restriction, including without limitation the rights to
  8. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  9. of the Software, and to permit persons to whom the Software is furnished to do
  10. so, subject to the following conditions:
  11.  
  12. The above copyright notice and this permission notice shall be included in all
  13. copies or substantial portions of the Software.
  14.  
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. SOFTWARE.
  22. ]]
  23.  
  24. --[[
  25. works on Lua 5.2
  26. data card not supported at the moment
  27. ]]
  28.  
  29. local fname = ...
  30.  
  31. local outdir = "results/"
  32.  
  33. local HACKS = true
  34.  
  35. -- detect if we're running on OC or a native system
  36. local sysnative = not not package.loadlib
  37.  
  38. -- readers
  39. function readu8(fp)
  40.     return fp:read(1):byte()
  41. end
  42. function readu16(fp)
  43.     local v1 = readu8(fp)
  44.     local v2 = readu8(fp)
  45.     return v1 + (v2*256)
  46. end
  47. function readu32(fp)
  48.     local v1 = readu16(fp)
  49.     local v2 = readu16(fp)
  50.     return v1 + (v2*65536)
  51. end
  52.  
  53. -- CRC32 implementation
  54. -- standard table lookup version
  55. do
  56.     local crctab = {}
  57.  
  58.     local i
  59.     for i=0,256-1 do
  60.         local j
  61.         local v = i
  62.  
  63.         for j=1,8 do
  64.             if bit32.band(v,1) == 0 then
  65.                 v = bit32.rshift(v, 1)
  66.             else
  67.                 v = bit32.rshift(v, 1)
  68.                 v = bit32.bxor(v, 0xEDB88320)
  69.             end
  70.         end
  71.         crctab[i+1] = v
  72.     end
  73.  
  74.     function crc32(str, v)
  75.         v = v or 0
  76.         v = bit32.bxor(v, 0xFFFFFFFF)
  77.  
  78.         local i
  79.         for i=1,#str do
  80.             --print(str:byte(i))
  81.             v = bit32.bxor(bit32.rshift(v, 8),
  82.                 crctab[bit32.bxor(bit32.band(v, 0xFF),
  83.                     str:byte(i))+1])
  84.         end
  85.  
  86.         v = bit32.bxor(v, 0xFFFFFFFF)
  87.         return v
  88.     end
  89. end
  90.  
  91. function inflate(data)
  92.     -- we aren't using data cards here
  93.     -- there is no zlib header in zip
  94.     local pos = 0
  95.     local ret = ""
  96.     local retcomb = ""
  97.  
  98.     local function get(sz)
  99.         local opos = pos
  100.         assert(sz >= 1)
  101.         if bit32.rshift(pos, 3) >= #data then error("unexpected EOF in deflate stream") end
  102.         local v = bit32.rshift(data:byte(bit32.rshift(pos, 3)+1), bit32.band(pos, 7))
  103.         local boffs = 0
  104.         if sz < 8-bit32.band(pos,7) then
  105.             pos = pos + sz
  106.         else
  107.             local boffs = (8-bit32.band(pos,7))
  108.             local brem = sz - boffs
  109.             pos = pos + boffs
  110.  
  111.             while brem > 8 do
  112.                 if bit32.rshift(pos,3) >= #data then error("unexpected EOF in deflate stream") end
  113.                 v = bit32.bor(v, bit32.lshift(
  114.                     data:byte(bit32.rshift(pos,3)+1), boffs))
  115.                 boffs = boffs + 8
  116.                 brem = brem - 8
  117.                 pos = pos + 8
  118.             end
  119.  
  120.             if brem > 0 then
  121.                 if bit32.rshift(pos,3) >= #data then error("unexpected EOF in deflate stream") end
  122.                 v = bit32.bor(v, bit32.lshift(data:byte(bit32.rshift(pos,3)+1), boffs))
  123.                 pos = pos + brem
  124.             end
  125.         end
  126.         assert(pos > opos)
  127.         return bit32.band(v, (bit32.lshift(1,sz)-1))
  128.     end
  129.  
  130.     local function buildhuff(tab, tablen)
  131.         local i
  132.         local lsort = {}
  133.  
  134.         -- categorise by length
  135.         for i=1,15 do lsort[i] = {} end
  136.         for i=1,tablen do
  137.             if tab[i] ~= 0 then
  138.                 table.insert(lsort[tab[i]], i-1)
  139.             end
  140.         end
  141.  
  142.         -- sort each by index
  143.         for i=1,15 do table.sort(lsort[i]) end
  144.  
  145.         -- build bit selection table
  146.         local llim = {}
  147.         local v = 0
  148.         for i=1,15 do
  149.             v = bit32.lshift(v, 1) + #lsort[i]
  150.             --print(i, v)
  151.             llim[i] = v
  152.             assert(v <= bit32.lshift(1, i))
  153.         end
  154.         assert(v == bit32.lshift(1, 15))
  155.  
  156.         return function()
  157.             local v = 0
  158.             local i
  159.             for i=1,15 do
  160.                 v = bit32.lshift(v, 1) + get(1)
  161.                 if v < llim[i] then
  162.                     return (lsort[i][1+(v-llim[i]+#lsort[i])] or
  163.                         error("lookup overflow"))
  164.                 end
  165.             end
  166.  
  167.             error("we seem to have an issue with this huffman tree")
  168.         end
  169.     end
  170.  
  171.     local bfinal = false
  172.     local btype
  173.  
  174.     local decoders = {}
  175.     decoders[1+1] = function()
  176.         local i
  177.  
  178.         -- literals
  179.         local hltab = {}
  180.         for i=0,143 do hltab[i+1] = 8 end
  181.         for i=144,255 do hltab[i+1] = 9 end
  182.         for i=256,279 do hltab[i+1] = 7 end
  183.         for i=280,287 do hltab[i+1] = 8 end
  184.  
  185.         -- distances
  186.         local hdtab = {}
  187.         for i=0,32-1 do hdtab[i+1] = 5 end
  188.  
  189.         -- build and return
  190.         local hltree = buildhuff(hltab, 288)
  191.         local hdtree = buildhuff(hdtab, 32)
  192.  
  193.         return hltree, hdtree
  194.     end
  195.     decoders[2+1] = function()
  196.         local i, j
  197.  
  198.         local hlit = get(5)+257
  199.         local hdist = get(5)+1
  200.         local hclen = get(4)+4
  201.         --print(hlit, hdist, hclen)
  202.  
  203.         local HCMAP = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
  204.         local hctab = {}
  205.  
  206.         -- code lengths
  207.         for i=0,18 do hctab[i+1] = 0 end
  208.         for i=1,hclen do
  209.             hctab[HCMAP[i]+1] = get(3)
  210.             --print(HCMAP[i], hctab[HCMAP[i]+1])
  211.         end
  212.         local hctree = buildhuff(hctab, 19)
  213.  
  214.         -- literals
  215.         local hltab = {}
  216.         i = 1
  217.         while i <= hlit do
  218.             local v = hctree()
  219.             if v <= 15 then
  220.                 hltab[i] = v
  221.                 i = i + 1
  222.             elseif v == 16 then
  223.                 assert(i >= 2)
  224.                 for j=1,get(2)+3 do
  225.                     hltab[i] = hltab[i-1]
  226.                     i = i + 1
  227.                 end
  228.             elseif v == 17 then
  229.                 for j=1,get(3)+3 do
  230.                     hltab[i] = 0
  231.                     i = i + 1
  232.                 end
  233.             elseif v == 18 then
  234.                 for j=1,get(7)+11 do
  235.                     hltab[i] = 0
  236.                     i = i + 1
  237.                 end
  238.             else
  239.                 error("hctree decoding issue")
  240.             end
  241.         end
  242.         assert(i == hlit+1)
  243.  
  244.         local hdtab = {}
  245.         i = 1
  246.         while i <= hdist do
  247.             local v = hctree()
  248.             if v <= 15 then
  249.                 hdtab[i] = v
  250.                 i = i + 1
  251.             elseif v == 16 then
  252.                 assert(i >= 2)
  253.                 for j=1,get(2)+3 do
  254.                     hdtab[i] = hdtab[i-1]
  255.                     i = i + 1
  256.                 end
  257.             elseif v == 17 then
  258.                 for j=1,get(3)+3 do
  259.                     hdtab[i] = 0
  260.                     i = i + 1
  261.                 end
  262.             elseif v == 18 then
  263.                 for j=1,get(7)+11 do
  264.                     hdtab[i] = 0
  265.                     i = i + 1
  266.                 end
  267.             else
  268.                 error("hctree decoding issue")
  269.             end
  270.         end
  271.         assert(i == hdist+1)
  272.  
  273.         local hltree = buildhuff(hltab, hlit)
  274.         local hdtree = buildhuff(hdtab, hdist)
  275.  
  276.         return hltree, hdtree
  277.     end
  278.  
  279.     local function lzss(len, dist)
  280.         if dist <= 3 then
  281.             dist = dist + 1
  282.         elseif dist <= 29 then
  283.             -- i refuse to type this whole thing out
  284.             local subdist = bit32.rshift((dist-4),1)
  285.             --print(dist)
  286.             local nd = get(subdist+1)
  287.             dist = (1 + bit32.lshift(1,(subdist+2))
  288.                 + bit32.lshift(bit32.band(dist,1),(subdist+1))
  289.                 + nd)
  290.             --print(dist, nd)
  291.         else
  292.             print(dist)
  293.             error("invalid deflate distance table code")
  294.         end
  295.  
  296.         -- TODO: optimise
  297.         assert(dist >= 1)
  298.         local i
  299.         local idx = #ret-dist+1
  300.         if idx < 1 then
  301.             -- pull back from combined return
  302.             ret = retcomb:sub(#retcomb+idx) .. ret
  303.             retcomb = retcomb:sub(1,#retcomb+idx-1)
  304.             idx = 1
  305.         end
  306.         assert(idx >= 1)
  307.         assert(idx <= #ret)
  308.         for i=1,len do
  309.             ret = ret .. ret:sub(idx, idx)
  310.             idx = idx + 1
  311.         end
  312.     end
  313.  
  314.     while not bfinal do
  315.         ret = ""
  316.         bfinal = (get(1) ~= 0)
  317.         btype = get(2)
  318.         if btype == 3 then error("invalid block mode") end
  319.         --if sysnative then print("block", btype, bfinal) end
  320.  
  321.         if btype == 0 then
  322.             pos = bit32.band((pos+7), bit32.bnot(7))
  323.             local lpos = bit32.rshift(pos, 3)
  324.             local len = data:byte(lpos+1)
  325.             len = len + (data:byte(lpos+2)*256)
  326.             local nlen = data:byte(lpos+3)
  327.             nlen = nlen + (data:byte(lpos+4)*256)
  328.             if bit32.bxor(len, nlen) ~= 0xFFFF then
  329.                 error("stored block complement check failed")
  330.             end
  331.             ret = data:sub(lpos+4+1, lpos+4+1+len-1)
  332.             assert(#ret == len)
  333.             pos = pos + 8*(4+len)
  334.         else
  335.  
  336.             local tfetch, tgetdist = decoders[btype+1]()
  337.  
  338.             while true do
  339.                 local v = tfetch()
  340.                 if v <= 255 then
  341.                     ret = ret .. string.char(v)
  342.                 elseif v == 256 then
  343.                     break
  344.                 elseif v >= 257 and v <= 264 then
  345.                     lzss(v-257 + 3, tgetdist())
  346.                 elseif v >= 265 and v <= 268 then
  347.                     lzss((v-265)*2 + 11 + get(1), tgetdist())
  348.                 elseif v >= 269 and v <= 272 then
  349.                     lzss((v-269)*4 + 19 + get(2), tgetdist())
  350.                 elseif v >= 273 and v <= 276 then
  351.                     lzss((v-273)*8 + 35 + get(3), tgetdist())
  352.                 elseif v >= 277 and v <= 280 then
  353.                     lzss((v-277)*16 + 67 + get(4), tgetdist())
  354.                 elseif v >= 281 and v <= 284 then
  355.                     lzss((v-281)*32 + 131 + get(5), tgetdist())
  356.                 elseif v >= 285 then
  357.                     lzss(258, tgetdist())
  358.                 else
  359.                     print(v)
  360.                     error("invalid deflate literal table code")
  361.                 end
  362.             end
  363.         end
  364.  
  365.         retcomb = retcomb .. ret
  366.         if not sysnative then os.sleep(0.05) end
  367.     end
  368.  
  369.     --print(#ret)
  370.     return retcomb
  371. end
  372.  
  373. assert(fname, "provide a filename as an argument")
  374.  
  375. -- check if we have a datacard
  376. if not sysnative then
  377.     pcall(function()
  378.         local component = require("component")
  379.         if component.data then
  380.             --print("FOUND DATA CARD")
  381.             --inflate = component.data.inflate
  382.             print("TODO: data card support")
  383.         end
  384.     end)
  385. end
  386.  
  387. infp = io.open(fname, "rb")
  388. while true do
  389.     -- ZIP file header (we unzip from file start here)
  390.     local magic = infp:read(4)
  391.     if magic ~= "PK\x03\x04" then
  392.         -- check for central directory header
  393.         if magic == "PK\x01\x02" then break end
  394.  
  395.         -- nope? ok, we've gone off the rails here
  396.         error("invalid zip magic")
  397.     end
  398.     zver = readu16(infp)
  399.     zflags = readu16(infp)
  400.     zcm = readu16(infp)
  401.     assert(zver <= 20, "we don't support features above zip 2.0")
  402.     --print(zflags)
  403.     assert(bit32.band(zflags, 0xF7F9) == 0, "zip relies on features we don't support (e.g. encraption)")
  404.     --assert(bit32.band(zflags, 0xF7F1) == 0, "zip relies on features we don't support (e.g. encraption)")
  405.     assert(zcm == 0 or zcm == 8, "we don't support stupid compression modes")
  406.     readu32(infp) -- last modified time, date
  407.     zcrc = readu32(infp)
  408.     zcsize = readu32(infp)
  409.     zusize = readu32(infp)
  410.     zfnlen = readu16(infp)
  411.     zeflen = readu16(infp)
  412.     assert(zfnlen >= 1, "extracting empty file name")
  413.     zfname = infp:read(zfnlen)
  414.     assert(zfname:len() == zfnlen)
  415.     zefield = infp:read(zeflen)
  416.     assert(zefield:len() == zeflen)
  417.     print("Extracting \""..zfname.."\" (csize="..zcsize..", usize="..zusize..")...")
  418.     cmpdata = infp:read(zcsize)
  419.     assert(cmpdata:len() == zcsize)
  420.  
  421.     if HACKS and zcrc == 1389383875 and zcsize == 87145 and zusize == 2189817 then
  422.         -- this file takes forever to uncompress
  423.         print("SKIPPED")
  424.     else
  425.         ucmpdata = ((zcm == 8 and inflate(cmpdata)) or cmpdata)
  426.         assert(ucmpdata:len() == zusize)
  427.         assert(crc32(ucmpdata) == bit32.band(zcrc, 0xFFFFFFFF), "CRC mismatch")
  428.  
  429.         if zfname:sub(-1) == "/" then
  430.             os.execute("mkdir -p \""..outdir..zfname.."\"")
  431.         else
  432.             outfp = io.open(outdir..zfname, "wb")
  433.             outfp:write(ucmpdata)
  434.             outfp:close()
  435.         end
  436.     end
  437. end
  438.  
  439.  
  440. -- TODO!
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement