From 6a845e40b485465d972b7f22b37bd0d1a1641b40 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Sun, 5 Feb 2017 22:29:55 +0100
Subject: Add a partial decoder for ZIP
---
plugins/zip.lua | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 plugins/zip.lua
(limited to 'plugins')
diff --git a/plugins/zip.lua b/plugins/zip.lua
new file mode 100644
index 0000000..a1b61de
--- /dev/null
+++ b/plugins/zip.lua
@@ -0,0 +1,81 @@
+--
+-- zip.lua: ZIP archives
+--
+-- Copyright (c) 2017, Přemysl Janouch
+--
+-- Permission to use, copy, modify, and/or distribute this software for any
+-- purpose with or without fee is hereby granted, provided that the above
+-- copyright notice and this permission notice appear in all copies.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+--
+
+-- Heuristics required, see https://en.wikipedia.org/wiki/Zip_(file_format)
+local detect = function (c)
+ c.endianity = "le"
+ for o = #c - 22 + 1, #c - 65535 - 22 + 1, -1 do
+ if o < 1 then break end
+ c.position = o
+ if c:u32 () == 0x06054b50 then return o end
+ end
+end
+
+local decode = function (c)
+ local eocd = detect (c ())
+ if not eocd then error ("not a ZIP file") end
+ c.endianity = "le"
+
+ c.position = eocd
+ c:u32 ("end of CD magic: %#x")
+ c:u16 ("# of this disk: %d")
+ c:u16 ("disk # where CD starts: %d")
+ local cd_len = c:u16 ("# of CD records on this disk: %d")
+ c:u16 ("total # of CD records: %d")
+ c:u32 ("size of CD: %d")
+ local cd_offset = c:u32 ("offset of (start of CD - start of archive): %d")
+ local comment_len = c:u16 ("comment length: %d")
+ c (c.position, c.position + comment_len - 1):mark ("comment")
+
+ -- TODO: decode the fields better
+ -- TODO: also mark actual file data if someone wants to put in the effort
+ c.position = cd_offset + 1
+ for i = 1, cd_len do
+ local p, magic = c.position, c:u32 ()
+ if magic ~= 0x02014b50 then break end
+ c (p, c.position - 1):mark ("CD file header magic: %#x", magic)
+ c:u16 ("version made by: %d")
+ c:u16 ("version needed to extract: %d")
+ c:u16 ("general purpose bit flag: %#x")
+ c:u16 ("compression method: %d")
+ c:u16 ("file last modification time: %d")
+ c:u16 ("file last modification date: %d")
+ c:u32 ("CRC-32: %#x")
+ c:u32 ("compressed size: %d")
+ c:u32 ("uncompressed size: %d")
+ local filename_len = c:u16 ("file name length: %d")
+ local extra_len = c:u16 ("extra field length: %d")
+ local comment_len = c:u16 ("file comment length: %d")
+ c:u16 ("disk # where file starts: %d")
+ c:u16 ("internal file attributes: %#x")
+ c:u32 ("external file attributes: %#x")
+ c:u32 ("offset of (start of local file header - start of archive): %d")
+
+ c (c.position, c.position + filename_len - 1):mark ("filename")
+ c.position = c.position + filename_len
+
+ c (c.position, c.position + extra_len - 1):mark ("extra field")
+ c.position = c.position + extra_len
+
+ c (c.position, c.position + comment_len - 1):mark ("file comment")
+ c.position = c.position + comment_len
+ end
+end
+
+hex.register { type="zip", detect=detect, decode=decode }
+
--
cgit v1.2.3-70-g09d2