Advertisement
MysticT

Package API

Aug 26th, 2013
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.52 KB | None | 0 0
  1. -- Package API v1.2.4
  2. -- by MysticT
  3.  
  4. --[[
  5. Package File:
  6.     - Package Header
  7.     - Format Version
  8.     - Number of Entries
  9.     - Entries:
  10.         - Type (file, directory)
  11.         - Name Size
  12.         - Entry Name
  13.         (Dir)
  14.             * Entries
  15.         (File)
  16.             * Contents Size
  17.             * File Contents
  18. --]]
  19.  
  20. local PKG_HEADER = "PKG"
  21. local PKG_VERSION = 0x12
  22.  
  23. local PKG_DIR_ENTRY = 0x00
  24. local PKG_FILE_ENTRY = 0x01
  25.  
  26. local lastYield = os.clock()
  27. local function yield()
  28.     if os.clock() - lastYield > 1 then
  29.         os.queueEvent("_yield_")
  30.         coroutine.yield("_yield_")
  31.         lastYield = os.clock()
  32.     end
  33. end
  34.  
  35. -- Read & Write Functions
  36.  
  37. local function getByte(n, i)
  38.     return bit.band(bit.brshift(n, i * 8), 0xFF)
  39. end
  40.  
  41. local function writeShort(file, i)
  42.     file.write(getByte(i, 0))
  43.     file.write(getByte(i, 1))
  44. end
  45.  
  46. local function writeBytes(file, s)
  47.     for i = 1, #s do
  48.         file.write(string.byte(s, i))
  49.         yield()
  50.     end
  51. end
  52.  
  53. local function writeString(file, str)
  54.     writeShort(file, #str)
  55.     writeBytes(file, str)
  56. end
  57.  
  58. local function readShort(file)
  59.     return file.read() + bit.blshift(file.read(), 8)
  60. end
  61.  
  62. local function readBytes(file, len)
  63.     local t = {}
  64.     for i = 1, len do
  65.         t[#t + 1] = string.char(file.read())
  66.         yield()
  67.     end
  68.     return table.concat(t)
  69. end
  70.  
  71. local function readString(file)
  72.     return readBytes(file, readShort(file))
  73. end
  74.  
  75. local function readFile(path)
  76.     local file = fs.open(path, "rb")
  77.     if not file then
  78.         return nil, "Error opening file "..tostring(path)
  79.     end
  80.     local t = {}
  81.     local c = file.read()
  82.     while c do
  83.         t[#t + 1] = string.char(c)
  84.         c = file.read()
  85.     end
  86.     return table.concat(t)
  87. end
  88.  
  89. -- Package Saving Functions
  90.  
  91. local function packFile(file, path)
  92.     local contents, err = readFile(path)
  93.     if not contents then
  94.         return false, err
  95.     end
  96.     writeString(file, contents)
  97.     return true
  98. end
  99.  
  100. local function packEntries(file, tEntries)
  101.     writeShort(file, #tEntries)
  102.     for i = 1, #tEntries do
  103.         local entry = tEntries[i]
  104.         file.write(entry.type)
  105.         writeString(file, entry.name)
  106.         local ok, err
  107.         if entry.type == PKG_DIR_ENTRY then
  108.             ok, err = packEntries(file, entry.entries)
  109.         else
  110.             ok, err = packFile(file, entry.path)
  111.         end
  112.         if not ok then
  113.             return false, err
  114.         end
  115.     end
  116.     return true
  117. end
  118.  
  119. local function makePackageFile(path)
  120.     local file = fs.open(path, "wb")
  121.     if not file then
  122.         return false, "Error opening file "..tostring(path)
  123.     end
  124.     -- Package Header
  125.     writeBytes(file, PKG_HEADER)
  126.     -- Format Version
  127.     file.write(PKG_VERSION)
  128.     return file
  129. end
  130.  
  131. local function getEntries(sPath)
  132.     local tEntries = {}
  133.     local list = fs.list(sPath)
  134.     for i = 1, #list do
  135.         local entry = {}
  136.         local path = fs.combine(sPath, list[i])
  137.         entry.name = list[i]
  138.         if fs.isDir(path) then
  139.             entry.type = PKG_DIR_ENTRY
  140.             entry.entries = getEntries(path)
  141.         else
  142.             entry.type = PKG_FILE_ENTRY
  143.             entry.path = path
  144.         end
  145.         tEntries[#tEntries + 1] = entry
  146.     end
  147.     return tEntries
  148. end
  149.  
  150. -- Package Loading Functions
  151.  
  152. local function loadEntries(file)
  153.     -- Number of Entries
  154.     local nEntries = readShort(file)
  155.     -- Entries
  156.     local tEntries = {}
  157.     for i = 1, nEntries do
  158.         -- Entry Type
  159.         local entry = {}
  160.         entry.type = file.read()
  161.         if entry.type == PKG_DIR_ENTRY then
  162.             -- TODO --
  163.             entry.name = readString(file)
  164.             local entries, err = loadEntries(file)
  165.             if not entries then
  166.                 return nil, err
  167.             end
  168.             entry.entries = entries
  169.         elseif entry.type == PKG_FILE_ENTRY then
  170.             entry.name = readString(file)
  171.             entry.contents = readString(file)
  172.         else
  173.             return nil, "Package file corrupted"
  174.         end
  175.         tEntries[#tEntries + 1] = entry
  176.     end
  177.     return tEntries
  178. end
  179.  
  180. -- Unpack Functions
  181.  
  182. local function unpackFile(path, entry)
  183.     local file = fs.open(path, "wb")
  184.     if not file then
  185.         return nil, "Error creating file "..tostring(path)
  186.     end
  187.     for i = 1, #entry.contents do
  188.         file.write(string.byte(entry.contents, i))
  189.         yield()
  190.     end
  191.     file.close()
  192.     return true
  193. end
  194.  
  195. local function unpackEntries(sPath, tEntries)
  196.     for i = 1, #tEntries do
  197.         local entry = tEntries[i]
  198.         local path = fs.combine(sPath, entry.name)
  199.         local ok, err
  200.         if entry.type == PKG_DIR_ENTRY then
  201.             fs.makeDir(path)
  202.             ok, err = unpackEntries(path, entry.entries)
  203.         else
  204.             ok, err = unpackFile(path, entry)
  205.         end
  206.         if not ok then
  207.             return false, err
  208.         end
  209.     end
  210.     return true
  211. end
  212.  
  213. -- API
  214.  
  215. function pack(path, outPath)
  216.     if not fs.exists(path) then
  217.         return false, "No such directory "..tostring(path)
  218.     end
  219.     if not fs.isDir(path) then
  220.         return false, "Not a directory"
  221.     end
  222.     local file, e = makePackageFile(outPath)
  223.     if not file then
  224.         return false, e
  225.     end
  226.     local ok, err = packEntries(file, getEntries(path))
  227.     file.close()
  228.     if not ok then
  229.         fs.delete(outPath)
  230.     end
  231.     return ok, err
  232. end
  233.  
  234. function load(path)
  235.     local file = fs.open(path, "rb")
  236.     if not file then
  237.         return nil, "Error opening file "..tostring(path)
  238.     end
  239.     -- Header
  240.     if readBytes(file, #PKG_HEADER) ~= PKG_HEADER then
  241.         file.close()
  242.         return nil, "Not a package file"
  243.     end
  244.     -- Version
  245.     local ver = file.read()
  246.     if ver ~= PKG_VERSION then
  247.         file.close()
  248.         return nil, string.format("Incompatible package version (%02X)", ver)
  249.     end
  250.     -- Entries
  251.     local tEntries, err = loadEntries(file)
  252.     file.close()
  253.     return tEntries, err
  254. end
  255.  
  256. function unpack(path, outPath)
  257.     if fs.exists(outPath) and not fs.isDir(outPath) then
  258.         return false, "Output path must be a directory"
  259.     elseif not fs.exists(outPath) then
  260.         return false, "No such directory "..tostring(outPath)
  261.     end
  262.     local tEntries, err = load(path)
  263.     if not tEntries then
  264.         return false, err
  265.     end
  266.     return unpackEntries(outPath, tEntries)
  267. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement