1. -- ************************************************************************
  2. -- Script:   GZIP
  3. -- Version:  0.3
  4. -- Date:     2009-08-08
  5. -- Author:   Valentin Schmidt
  6. --
  7. -- implements GZIP compression according to RFC1952 (http://www.faqs.org/rfcs/rfc1952)
  8. -- data is e.g. compatible with the GZIP commandline tool or PHP's gzencode() function.
  9. --
  10. -- Notice: unfortunately the current implementation of the compress/uncompress functions of director's bytearray class use
  11. -- ZLIB (i.e. gzcompress) instead of raw DEFLATE compression. this is no limitation for compressing data (as
  12. -- DEFLATE/GZIP/ZIP files) since the 6 additional ZLIB bytes (2 bytes at the beginning, 4 adler32 checksum bytes at the end)
  13. -- just need to be removed to create valid DEFLATE compressed data (that can then be used to create GZIP/ZIP files). but
  14. -- unfortunately the bytearray's uncompress() function fails if the 4 adler32 checksum bytes at the end of the bytearray are
  15. -- missing or incorrect, and therefor INFLATE, GZIP and ZIP decompression is only possible if the adler32 checksums of the
  16. -- original file(s) are known.
  17. -- one way to lessen this strong limitation a little bit, so at least GZIP and ZIP files created with those scripts can be
  18. -- decompressed without requiring any additional info, is to store the adler32 checksums as comments inside the GZP/ZIP file.
  19. -- such files can be decompresssed with any 3rd party tool (which just ignore the comments) as well as with code based on
  20. -- byterrays's uncompress function.
  21. --
  22. -- Requirements:
  23. -- * fileIO xtra
  24. -- * fileIO wrapper functions file_get_bytes()/file_put_bytes()
  25. -- * str_replace() function
  26. -- * crc32_bytearray() function (or alternatively an xtra for faster CRC32 calculation, e.g. crypto xtra)
  27. --
  28. -- ************************************************************************
  29.  
  30. ----------------------------------------
  31. -- NOTICE:
  32. -- passed bytearray baInput is changed (bytearray is compressed)!!!
  33. -- if this is not wanted, either create a copy or use ba.uncompress to restore original state
  34. ----------------------------------------
  35. on gzip_encode_bytearray (baInput, tFilename, tComment, tDate)
  36.  
  37.   info = [:]
  38.   crc32 = crc32_bytearray(baInput)
  39.   orgLen = baInput.length
  40.   baInput.compress()
  41.  
  42.   baInput.position = baInput.length-3
  43.   baInput.endian=#bigEndian
  44.   info["adler32"] = baInput.readInt32()
  45.  
  46.   baOutput = bytearray()
  47.   flags = 0
  48.   if not voidP(tFilename) then flags = flags + 8
  49.   if not voidP(tComment) then flags = flags + 16
  50.  
  51.   if voidP(tDate) then tDate = the systemdate
  52.   unixTime = dateToUnixTime(tDate)
  53.  
  54.   baOutput.writeInt8(31)
  55.   baOutput.writeInt8(139)
  56.   baOutput.writeInt8(8)
  57.   baOutput.writeInt8(flags)
  58.   baOutput.writeInt32(unixTime)
  59.   baOutput.writeInt8(2)
  60.   baOutput.writeInt8(255) -- ???
  61.  
  62.   if not voidP(tFilename) then
  63.     if the platform contains "win" then
  64.       tFilename = str_replace("\", "/", tFilename)
  65.     else
  66.       tFilename = str_replace(":", "/", tFilename)
  67.     end if
  68.     baOutput.writeRawString(tFilename, tFilename.length)
  69.     baOutput.writeInt8(0)
  70.   end if
  71.  
  72.   if not voidP(tComment) then
  73.     if tComment=#adler32 then
  74.       tComment = string(info["adler32"])
  75.     end if
  76.     baOutput.writeRawString(tComment, tComment.length)
  77.     baOutput.writeInt8(0)
  78.   end if
  79.  
  80.   baOutput.writeByteArray(baInput, 3, baInput.length-6) -- remove header and adler32 checksum bytes
  81.   baOutput.writeInt32( crc32 )
  82.   baOutput.writeInt32( orgLen )
  83.  
  84.   info["data"] = baOutput
  85.   return info
  86. end
  87.  
  88. ----------------------------------------
  89. --
  90. ----------------------------------------
  91. on gzip_encode_file (inputFile, outputFile, tComment, tDate)
  92.   if voidP(outputFile) then
  93.     outputFile = inputFile & ".gz"
  94.   end if
  95.   baInput = file_get_bytes(inputFile)
  96.  
  97.   -- get filename from path
  98.   od = the itemdelimiter
  99.   the itemdelimiter = the last char of _movie.path
  100.   inputFileName = the last item of inputFile
  101.   the itemdelimiter = od
  102.  
  103.   info = gzip_encode_bytearray (baInput, inputFileName, tComment, tDate)
  104.   file_put_bytes(outputFile, info["data"])
  105.   return info["adler32"]
  106. end
  107.  
  108. ----------------------------------------
  109. -- uncompress gzip-encoded data (unfortunately only possible if adler32 checksum is known)
  110. ----------------------------------------
  111. on gzip_decode_bytearray (baInput, adler32)
  112.   info = [:]
  113.  
  114.   flags = baInput[4]
  115.  
  116.   baInput.position = 5
  117.   unixTime = baInput.readInt32()
  118.   info["date"] = unixTimeToDate(unixTime)
  119.  
  120.   startPos = 11
  121.   if bitand(flags, 8) then
  122.     baInput.position = startPos
  123.     repeat while baInput[startPos]<>0
  124.       startPos=startPos+1
  125.     end repeat
  126.     info["filename"] = baInput.readRawString(startPos-baInput.position)
  127.     startPos=startPos+1
  128.   end if
  129.  
  130.   if bitand(flags, 16) then
  131.     baInput.position = startPos
  132.     repeat while baInput[startPos]<>0
  133.       startPos=startPos+1
  134.     end repeat
  135.     info["comment"] = baInput.readRawString(startPos-baInput.position)
  136.     startPos=startPos+1
  137.   end if
  138.  
  139.   if adler32=#comment then -- adler32 stored as comment
  140.     if voidP(info["comment"]) then
  141.       -- error
  142.     else
  143.       adler32 = integer(info["comment"])
  144.     end if
  145.   end if
  146.  
  147.   baInput.position = startPos
  148.   tmp = baInput.readByteArray(baInput.length-startPos-8+1)
  149.  
  150.   -- INFLATE
  151.   data = bytearray(tmp.length+6)
  152.   data[1] = 120
  153.   data[2] = 218
  154.   data.position = 3
  155.   data.writeByteArray(tmp)
  156.   data.endian = #bigEndian
  157.   data.writeInt32(adler32)
  158.   data.uncompress()
  159.   info["data"] = data
  160.  
  161.   return info
  162. end
  163.  
  164. ----------------------------------------
  165. -- uncompress gzip-encoded data (unfortunately only possible if adler32 checksum is known)
  166. ----------------------------------------
  167. on gzip_decode_file (inputFile, outputFile, adler32)
  168.   baInput = file_get_bytes(inputFile)
  169.   info = gzip_decode_bytearray (baInput, adler32)
  170.   if voidP(outputFile) then
  171.     od = the itemdelimiter
  172.     pd = the last char of _movie.path
  173.     the itemdelimiter = pd
  174.     outputFile = inputFile
  175.     delete the last item of outputFile
  176.     put pd after outputFile
  177.     if not voidP(info["filename"]) then -- extract filename from GZIP file?
  178.       put info["filename"] after outputFile
  179.     else -- else extract filename from GZIP filename
  180.       inputFileName = the last item of inputFile
  181.       the itemdelimiter = "."
  182.       delete the last item of inputFileName
  183.       put inputFileName after outputFile
  184.     end if
  185.     the itemdelimiter = od
  186.   end if
  187.   file_put_bytes(outputFile, info["data"])
  188.   return info
  189. end
  190.  
  191. ----------------------------------------
  192. --
  193. ----------------------------------------
  194. on dateToUnixTime (tDate)
  195.   days = tDate - date(1970, 1, 1)
  196.   return days*24*60*60 + tDate.seconds
  197. end
  198.  
  199. ----------------------------------------
  200. --
  201. ----------------------------------------
  202. on unixTimeToDate (unixTime)  
  203.   tDate = date(1970, 1, 1)
  204.   days = unixTime / 86400
  205.   tDate = tDate + days
  206.   tDate.seconds = unixTime mod 86400
  207.   return tDate
  208. end
  209.  
[raw code]