--- /dev/null
+local security = minetest.request_insecure_environment()
+
+local path = minetest.get_modpath(minetest.get_current_modname())
+
+local pngimage = dofile(path.."/png_lua/png.lua")
+
+--run through all the skins on the skindex and index them all locally
+--only try to index further than the point in the current list max
+
+local http = minetest.request_http_api()
+local id = "Lua Skins Updater"
+-- Binary downloads are required
+if not core.features.httpfetch_binary_data then
+ print("outdated version of MINETEST detected!")
+end
+
+if not http or not security then
+ for i = 1,5 do
+ print("!WARNING!")
+ end
+ print("---------------------------------------------------------------")
+ print("HTTP access is required. Please add this to your minetest.conf:")
+ print("secure.http_mods = skins")
+ print("secure.trusted_mods = skins")
+ print("!!Skins will not work without this!!")
+ print("---------------------------------------------------------------")
+ return(nil)
+end
+
+
+-- http://minetest.fensta.bplaced.net/api/apidoku.md
+local root_url = "http://minetest.fensta.bplaced.net"
+local page_url = root_url .. "/api/v2/get.json.php?getlist&page=%i&outformat=base64" -- [1] = Page#
+local preview_url = root_url .. "/skins/1/%i.png" -- [1] = ID
+
+-- Fancy debug wrapper to download an URL
+local function fetch_url(url, callback)
+ http.fetch({
+ url = url,
+ timeout = 3,
+ }, function(result)
+ print(dump(result))
+ if result.succeeded then
+
+ --if result.code ~= 200 then
+ --core.log("warning", ("%s: STATUS=%i URL=%s"):format(
+ -- _ID_, result.code, url))
+ --end
+ return callback(result.data)
+ end
+ core.log("warning", ("%s: Failed to download URL=%s"):format(
+ id, url))
+ end)
+end
+
+local function unsafe_file_write(path, contents)
+ local f = security.io.open(path, "wb")
+ f:write(contents)
+ f:close()
+end
+
+--https://gist.github.com/marceloCodget/3862929 rgb to hex
+
+local function rgbToHex(rgb)
+ local hexadecimal = '0X'
+
+ for key, value in pairs(rgb) do
+ local hex = ''
+
+ while(value > 0)do
+ local index = math.fmod(value, 16) + 1
+ value = math.floor(value / 16)
+ hex = string.sub('0123456789ABCDEF', index, index) .. hex
+ end
+
+ if(string.len(hex) == 0)then
+ hex = '00'
+
+ elseif(string.len(hex) == 1)then
+ hex = '0' .. hex
+ end
+
+ hexadecimal = hexadecimal .. hex
+ end
+
+ return hexadecimal
+end
+
+local xmax = 64
+local ymax = 32
+local function file_to_texture(image)
+ local x = 1
+ local y = 1
+ --local base_texture = "[combine:"..xmax.."x"..ymax
+ local base_texture = "[combine:" .. xmax .. "x" .. ymax
+ --local base_texture2 = "[combine:"..xmax.."x"..ymax
+ for _,line in pairs(image.pixels) do
+ for _,data in pairs(line) do
+ if x <= 32 or y > 16 then
+ local hex = rgbToHex({data.R,data.G,data.B}):sub(3)
+ base_texture = base_texture .. (":%s,%s=%s"):format(x - 1, y - 1, "(p.png\\^[colorize\\:#" .. hex .. ")")
+ --else
+ -- print(dump(data))
+ end
+ x = x + 1
+ if x > xmax then
+ x = 1
+ y = y + 1
+ end
+ if y > ymax then
+ break
+ end
+ end
+ end
+ return(base_texture)
+end
+
+-- Function to fetch a range of pages
+fetch_function = function()
+ fetch_url("https://raw.githubusercontent.com/oilboi/crafter_skindex/master/skin.png", function(data)
+ if data then
+ unsafe_file_write(path.."/skin_temp/temp.png", data)
+
+ local img = pngimage(minetest.get_modpath("skins").."/skin_temp/temp.png", nil, false, false)
+ if img then
+ local stored_texture = file_to_texture(img)
+
+ --print("===============================================================")
+ --print(stored_texture)
+ if stored_texture then
+ --print(dump(stored_texture))
+ minetest.get_player_by_name("singleplayer"):set_properties({textures = {stored_texture}})
+ --[[
+ minetest.get_player_by_name("singleplayer"):hud_add(
+ {
+ hud_elem_type = "image", -- See HUD element types
+ -- Type of element, can be "image", "text", "statbar", or "inventory"
+
+ position = {x=0.5, y=0.5},
+ -- Left corner position of element
+
+ name = "<name>",
+
+ scale = {x = 2, y = 2},
+
+ text = stored_texture,
+
+ text2 = "<text>",
+
+ number = 2,
+
+ item = 3,
+ -- Selected item in inventory. 0 for no item selected.
+
+ direction = 0,
+ -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
+
+ alignment = {x=0, y=0},
+
+ offset = {x=0, y=0},
+
+ size = { x=100, y=100 },
+ -- Size of element in pixels
+
+ z_index = 0,
+ -- Z index : lower z-index HUDs are displayed behind higher z-index HUDs
+ }
+ )
+ ]]--
+ end
+ end
+
+ end
+ end)
+end
+
+--local img = pngimage(minetest.get_modpath("skins").."/skin_temp/temp.png", nil, false, false)
+--print(dump(img))
+
+minetest.register_on_joinplayer(function(player)
+ minetest.after(4,function()
+ fetch_function()
+ end)
+end)
\ No newline at end of file
--- /dev/null
+--[[
+
+LUA MODULE
+
+compress.deflatelua - deflate (and gunzip/zlib) implemented in Lua.
+
+SYNOPSIS
+local DEFLATE = require 'compress.deflatelua'
+-- uncompress gzip file
+local fh = assert(io.open'foo.txt.gz', 'rb')
+local ofh = assert(io.open'foo.txt', 'wb')
+DEFLATE.gunzip {input=fh, output=ofh}
+fh:close(); ofh:close()
+-- can also uncompress from string including zlib and raw DEFLATE formats.
+DESCRIPTION
+This is a pure Lua implementation of decompressing the DEFLATE format,
+including the related zlib and gzip formats.
+Note: This library only supports decompression.
+Compression is not currently implemented.
+
+API
+
+Note: in the following functions, input stream `fh` may be
+a file handle, string, or an iterator function that returns strings.
+Output stream `ofh` may be a file handle or a function that
+consumes one byte (number 0..255) per call.
+
+DEFLATE.inflate {input=fh, output=ofh}
+
+Decompresses input stream `fh` in the DEFLATE format
+while writing to output stream `ofh`.
+DEFLATE is detailed in http://tools.ietf.org/html/rfc1951 .
+DEFLATE.gunzip {input=fh, output=ofh, disable_crc=disable_crc}
+Decompresses input stream `fh` with the gzip format
+while writing to output stream `ofh`.
+`disable_crc` (defaults to `false`) will disable CRC-32 checking
+to increase speed.
+gzip is detailed in http://tools.ietf.org/html/rfc1952 .
+
+DEFLATE.inflate_zlib {input=fh, output=ofh, disable_crc=disable_crc}
+Decompresses input stream `fh` with the zlib format
+while writing to output stream `ofh`.
+`disable_crc` (defaults to `false`) will disable CRC-32 checking
+to increase speed.
+zlib is detailed in http://tools.ietf.org/html/rfc1950 .
+
+DEFLATE.adler32(byte, crc) --> rcrc
+Returns adler32 checksum of byte `byte` (number 0..255) appended
+to string with adler32 checksum `crc`. This is internally used by
+`inflate_zlib`.
+ADLER32 in detailed in http://tools.ietf.org/html/rfc1950 .
+
+COMMAND LINE UTILITY
+
+A `gunziplua` command line utility (in folder `bin`) is also provided.
+This mimicks the *nix `gunzip` utility but is a pure Lua implementation
+that invokes this library. For help do
+gunziplua -h
+DEPENDENCIES
+
+Requires 'digest.crc32lua' (used for optional CRC-32 checksum checks).
+https://github.com/davidm/lua-digest-crc32lua
+
+Will use a bit library ('bit', 'bit32', 'bit.numberlua') if available. This
+is not that critical for this library but is required by digest.crc32lua.
+
+'pythonic.optparse' is only required by the optional `gunziplua`
+command-line utilty for command line parsing.
+https://github.com/davidm/lua-pythonic-optparse
+
+INSTALLATION
+
+Copy the `compress` directory into your LUA_PATH.
+REFERENCES
+
+[1] DEFLATE Compressed Data Format Specification version 1.3
+http://tools.ietf.org/html/rfc1951
+[2] GZIP file format specification version 4.3
+http://tools.ietf.org/html/rfc1952
+[3] http://en.wikipedia.org/wiki/DEFLATE
+[4] pyflate, by Paul Sladen
+http://www.paul.sladen.org/projects/pyflate/
+[5] Compress::Zlib::Perl - partial pure Perl implementation of
+Compress::Zlib
+http://search.cpan.org/~nwclark/Compress-Zlib-Perl/Perl.pm
+
+LICENSE
+
+(c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+(end license)
+--]]
+
+
+local M = {_TYPE='module', _NAME='compress.deflatelua', _VERSION='0.3.20111128'}
+
+local assert = assert
+local error = error
+local ipairs = ipairs
+local pairs = pairs
+local print = print
+local require = require
+local tostring = tostring
+local type = type
+local setmetatable = setmetatable
+local io = io
+local math = math
+local table_sort = table.sort
+local math_max = math.max
+local string_char = string.char
+
+--[[
+Requires the first module listed that exists, else raises like `require`.
+If a non-string is encountered, it is returned.
+Second return value is module name loaded (or '').
+--]]
+local function requireany(...)
+ local errs = {}
+ for i = 1, select('#', ...) do local name = select(i, ...)
+ if type(name) ~= 'string' then return name, '' end
+ local ok, mod = pcall(require, name)
+ if ok then return mod, name end
+ errs[#errs+1] = mod
+ end
+ error(table.concat(errs, '\n'), 2)
+end
+
+
+--local crc32 = require "digest.crc32lua" . crc32_byte
+local bit, name_ = requireany('bit', 'bit32', 'bit.numberlua', nil)
+
+local DEBUG = false
+
+-- Whether to use `bit` library functions in current module.
+-- Unlike the crc32 library, it doesn't make much difference in this module.
+local NATIVE_BITOPS = (bit ~= nil)
+
+local band, lshift, rshift
+if NATIVE_BITOPS then
+ band = bit.band
+ lshift = bit.lshift
+ rshift = bit.rshift
+end
+
+
+local function warn(s)
+ io.stderr:write(s, '\n')
+end
+
+
+local function debug(...)
+ print('DEBUG', ...)
+end
+
+
+local function runtime_error(s, level)
+ level = level or 1
+ error({s}, level+1)
+end
+
+
+local function make_outstate(outbs)
+ local outstate = {}
+ outstate.outbs = outbs
+ outstate.window = {}
+ outstate.window_pos = 1
+ return outstate
+end
+
+
+local function output(outstate, byte)
+ -- debug('OUTPUT:', s)
+ local window_pos = outstate.window_pos
+ outstate.outbs(byte)
+ outstate.window[window_pos] = byte
+ outstate.window_pos = window_pos % 32768 + 1 -- 32K
+end
+
+
+local function noeof(val)
+ return assert(val, 'unexpected end of file')
+end
+
+
+local function hasbit(bits, bit)
+ return bits % (bit + bit) >= bit
+end
+
+
+local function memoize(f)
+ local mt = {}
+ local t = setmetatable({}, mt)
+ function mt:__index(k)
+ local v = f(k)
+ t[k] = v
+ return v
+ end
+ return t
+end
+
+
+-- small optimization (lookup table for powers of 2)
+local pow2 = memoize(function(n) return 2^n end)
+
+--local tbits = memoize(
+-- function(bits)
+-- return memoize( function(bit) return getbit(bits, bit) end )
+-- end )
+
+
+-- weak metatable marking objects as bitstream type
+local is_bitstream = setmetatable({}, {__mode='k'})
+
+
+-- DEBUG
+-- prints LSB first
+--[[
+local function bits_tostring(bits, nbits)
+local s = ''
+local tmp = bits
+local function f()
+local b = tmp % 2 == 1 and 1 or 0
+s = s .. b
+tmp = (tmp - b) / 2
+end
+if nbits then
+for i=1,nbits do f() end
+else
+while tmp ~= 0 do f() end
+end
+
+return s
+end
+--]]
+
+local function bytestream_from_file(fh)
+ local o = {}
+ function o:read()
+ local sb = fh:read(1)
+ if sb then return sb:byte() end
+ end
+ return o
+end
+
+
+local function bytestream_from_string(s)
+ local i = 1
+ local o = {}
+ function o:read()
+ local by
+ if i <= #s then
+ by = s:byte(i)
+ i = i + 1
+ end
+ return by
+ end
+ return o
+end
+
+
+local function bytestream_from_function(f)
+ local i = 0
+ local buffer = ''
+ local o = {}
+ function o:read()
+ i = i + 1
+ if i > #buffer then
+ buffer = f()
+ if not buffer then return end
+ i = 1
+ end
+ return buffer:byte(i,i)
+ end
+ return o
+end
+
+
+local function bitstream_from_bytestream(bys)
+ local buf_byte = 0
+ local buf_nbit = 0
+ local o = {}
+
+ function o:nbits_left_in_byte()
+ return buf_nbit
+ end
+
+ if NATIVE_BITOPS then
+ function o:read(nbits)
+ nbits = nbits or 1
+ while buf_nbit < nbits do
+ local byte = bys:read()
+ if not byte then return end -- note: more calls also return nil
+ buf_byte = buf_byte + lshift(byte, buf_nbit)
+ buf_nbit = buf_nbit + 8
+ end
+ local bits
+ if nbits == 0 then
+ bits = 0
+ elseif nbits == 32 then
+ bits = buf_byte
+ buf_byte = 0
+ else
+ bits = band(buf_byte, rshift(0xffffffff, 32 - nbits))
+ buf_byte = rshift(buf_byte, nbits)
+ end
+ buf_nbit = buf_nbit - nbits
+ return bits
+ end
+ else
+ function o:read(nbits)
+ nbits = nbits or 1
+ while buf_nbit < nbits do
+ local byte = bys:read()
+ if not byte then return end -- note: more calls also return nil
+ buf_byte = buf_byte + pow2[buf_nbit] * byte
+ buf_nbit = buf_nbit + 8
+ end
+ local m = pow2[nbits]
+ local bits = buf_byte % m
+ buf_byte = (buf_byte - bits) / m
+ buf_nbit = buf_nbit - nbits
+ return bits
+ end
+ end
+
+ is_bitstream[o] = true
+
+ return o
+end
+
+
+local function get_bitstream(o)
+ local bs
+ if is_bitstream[o] then
+ return o
+ elseif io.type(o) == 'file' then
+ bs = bitstream_from_bytestream(bytestream_from_file(o))
+ elseif type(o) == 'string' then
+ bs = bitstream_from_bytestream(bytestream_from_string(o))
+ elseif type(o) == 'function' then
+ bs = bitstream_from_bytestream(bytestream_from_function(o))
+ else
+ runtime_error 'unrecognized type'
+ end
+ return bs
+end
+
+
+local function get_obytestream(o)
+ local bs
+ if io.type(o) == 'file' then
+ bs = function(sbyte) o:write(string_char(sbyte)) end
+ elseif type(o) == 'function' then
+ bs = o
+ else
+ runtime_error('unrecognized type: ' .. tostring(o))
+ end
+ return bs
+end
+
+
+local function HuffmanTable(init, is_full)
+ local t = {}
+ if is_full then
+ for val,nbits in pairs(init) do
+ if nbits ~= 0 then
+ t[#t+1] = {val=val, nbits=nbits}
+ --debug('*',val,nbits)
+ end
+ end
+ else
+ for i=1,#init-2,2 do
+ local firstval, nbits, nextval = init[i], init[i+1], init[i+2]
+ --debug(val, nextval, nbits)
+ if nbits ~= 0 then
+ for val=firstval,nextval-1 do
+ t[#t+1] = {val=val, nbits=nbits}
+ end
+ end
+ end
+ end
+ table_sort(t, function(a,b)
+ return a.nbits == b.nbits and a.val < b.val or a.nbits < b.nbits
+ end)
+
+ -- assign codes
+ local code = 1 -- leading 1 marker
+ local nbits = 0
+ for i,s in ipairs(t) do
+ if s.nbits ~= nbits then
+ code = code * pow2[s.nbits - nbits]
+ nbits = s.nbits
+ end
+ s.code = code
+ --debug('huffman code:', i, s.nbits, s.val, code, bits_tostring(code))
+ code = code + 1
+ end
+
+ local minbits = math.huge
+ local look = {}
+ for i,s in ipairs(t) do
+ minbits = math.min(minbits, s.nbits)
+ look[s.code] = s.val
+ end
+
+ --for _,o in ipairs(t) do
+ -- debug(':', o.nbits, o.val)
+ --end
+
+ -- function t:lookup(bits) return look[bits] end
+
+ local msb = NATIVE_BITOPS and function(bits, nbits)
+ local res = 0
+ for i=1,nbits do
+ res = lshift(res, 1) + band(bits, 1)
+ bits = rshift(bits, 1)
+ end
+ return res
+ end or function(bits, nbits)
+ local res = 0
+ for i=1,nbits do
+ local b = bits % 2
+ bits = (bits - b) / 2
+ res = res * 2 + b
+ end
+ return res
+ end
+
+ local tfirstcode = memoize(
+ function(bits) return pow2[minbits] + msb(bits, minbits) end)
+
+ function t:read(bs)
+ local code = 1 -- leading 1 marker
+ local nbits = 0
+ while 1 do
+ if nbits == 0 then -- small optimization (optional)
+ code = tfirstcode[noeof(bs:read(minbits))]
+ nbits = nbits + minbits
+ else
+ local b = noeof(bs:read())
+ nbits = nbits + 1
+ code = code * 2 + b -- MSB first
+ --[[NATIVE_BITOPS
+code = lshift(code, 1) + b -- MSB first
+--]]
+ end
+ --debug('code?', code, bits_tostring(code))
+ local val = look[code]
+ if val then
+ --debug('FOUND', val)
+ return val
+ end
+ end
+ end
+
+ return t
+end
+
+
+local function parse_gzip_header(bs)
+ -- local FLG_FTEXT = 2^0
+ local FLG_FHCRC = 2^1
+ local FLG_FEXTRA = 2^2
+ local FLG_FNAME = 2^3
+ local FLG_FCOMMENT = 2^4
+
+ local id1 = bs:read(8)
+ local id2 = bs:read(8)
+ if id1 ~= 31 or id2 ~= 139 then
+ runtime_error 'not in gzip format'
+ end
+ local cm = bs:read(8) -- compression method
+ local flg = bs:read(8) -- FLaGs
+ local mtime = bs:read(32) -- Modification TIME
+ local xfl = bs:read(8) -- eXtra FLags
+ local os = bs:read(8) -- Operating System
+
+ if DEBUG then
+ debug("CM=", cm)
+ debug("FLG=", flg)
+ debug("MTIME=", mtime)
+ -- debug("MTIME_str=",os.date("%Y-%m-%d %H:%M:%S",mtime)) -- non-portable
+ debug("XFL=", xfl)
+ debug("OS=", os)
+ end
+
+ if not os then runtime_error 'invalid header' end
+
+ if hasbit(flg, FLG_FEXTRA) then
+ local xlen = bs:read(16)
+ local extra = 0
+ for i=1,xlen do
+ extra = bs:read(8)
+ end
+ if not extra then runtime_error 'invalid header' end
+ end
+
+ local function parse_zstring(bs)
+ repeat
+ local by = bs:read(8)
+ if not by then runtime_error 'invalid header' end
+ until by == 0
+ end
+
+ if hasbit(flg, FLG_FNAME) then
+ parse_zstring(bs)
+ end
+
+ if hasbit(flg, FLG_FCOMMENT) then
+ parse_zstring(bs)
+ end
+
+ if hasbit(flg, FLG_FHCRC) then
+ local crc16 = bs:read(16)
+ if not crc16 then runtime_error 'invalid header' end
+ -- IMPROVE: check CRC. where is an example .gz file that
+ -- has this set?
+ if DEBUG then
+ debug("CRC16=", crc16)
+ end
+ end
+end
+
+local function parse_zlib_header(bs)
+ local cm = bs:read(4) -- Compression Method
+ local cinfo = bs:read(4) -- Compression info
+ local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG)
+ local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary)
+ local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level)
+ local cmf = cinfo * 16 + cm -- CMF (Compresion Method and flags)
+ local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs
+
+ if cm ~= 8 then -- not "deflate"
+ runtime_error("unrecognized zlib compression method: " .. cm)
+ end
+ if cinfo > 7 then
+ runtime_error("invalid zlib window size: cinfo=" .. cinfo)
+ end
+ local window_size = 2^(cinfo + 8)
+
+ if (cmf*256 + flg) % 31 ~= 0 then
+ runtime_error("invalid zlib header (bad fcheck sum)")
+ end
+
+ if fdict == 1 then
+ runtime_error("FIX:TODO - FDICT not currently implemented")
+ local dictid_ = bs:read(32)
+ end
+
+ return window_size
+end
+
+local function parse_huffmantables(bs)
+ local hlit = bs:read(5) -- # of literal/length codes - 257
+ local hdist = bs:read(5) -- # of distance codes - 1
+ local hclen = noeof(bs:read(4)) -- # of code length codes - 4
+
+ local ncodelen_codes = hclen + 4
+ local codelen_init = {}
+ local codelen_vals = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+ for i=1,ncodelen_codes do
+ local nbits = bs:read(3)
+ local val = codelen_vals[i]
+ codelen_init[val] = nbits
+ end
+ local codelentable = HuffmanTable(codelen_init, true)
+
+ local function decode(ncodes)
+ local init = {}
+ local nbits
+ local val = 0
+ while val < ncodes do
+ local codelen = codelentable:read(bs)
+ --FIX:check nil?
+ local nrepeat
+ if codelen <= 15 then
+ nrepeat = 1
+ nbits = codelen
+ --debug('w', nbits)
+ elseif codelen == 16 then
+ nrepeat = 3 + noeof(bs:read(2))
+ -- nbits unchanged
+ elseif codelen == 17 then
+ nrepeat = 3 + noeof(bs:read(3))
+ nbits = 0
+ elseif codelen == 18 then
+ nrepeat = 11 + noeof(bs:read(7))
+ nbits = 0
+ else
+ error 'ASSERT'
+ end
+ for i=1,nrepeat do
+ init[val] = nbits
+ val = val + 1
+ end
+ end
+ local huffmantable = HuffmanTable(init, true)
+ return huffmantable
+ end
+
+ local nlit_codes = hlit + 257
+ local ndist_codes = hdist + 1
+
+ local littable = decode(nlit_codes)
+ local disttable = decode(ndist_codes)
+
+ return littable, disttable
+end
+
+
+local tdecode_len_base
+local tdecode_len_nextrabits
+local tdecode_dist_base
+local tdecode_dist_nextrabits
+local function parse_compressed_item(bs, outstate, littable, disttable)
+ local val = littable:read(bs)
+ --debug(val, val < 256 and string_char(val))
+ if val < 256 then -- literal
+ output(outstate, val)
+ elseif val == 256 then -- end of block
+ return true
+ else
+ if not tdecode_len_base then
+ local t = {[257]=3}
+ local skip = 1
+ for i=258,285,4 do
+ for j=i,i+3 do t[j] = t[j-1] + skip end
+ if i ~= 258 then skip = skip * 2 end
+ end
+ t[285] = 258
+ tdecode_len_base = t
+ --for i=257,285 do debug('T1',i,t[i]) end
+ end
+ if not tdecode_len_nextrabits then
+ local t = {}
+ if NATIVE_BITOPS then
+ for i=257,285 do
+ local j = math_max(i - 261, 0)
+ t[i] = rshift(j, 2)
+ end
+ else
+ for i=257,285 do
+ local j = math_max(i - 261, 0)
+ t[i] = (j - (j % 4)) / 4
+ end
+ end
+ t[285] = 0
+ tdecode_len_nextrabits = t
+ --for i=257,285 do debug('T2',i,t[i]) end
+ end
+ local len_base = tdecode_len_base[val]
+ local nextrabits = tdecode_len_nextrabits[val]
+ local extrabits = bs:read(nextrabits)
+ local len = len_base + extrabits
+
+ if not tdecode_dist_base then
+ local t = {[0]=1}
+ local skip = 1
+ for i=1,29,2 do
+ for j=i,i+1 do t[j] = t[j-1] + skip end
+ if i ~= 1 then skip = skip * 2 end
+ end
+ tdecode_dist_base = t
+ --for i=0,29 do debug('T3',i,t[i]) end
+ end
+ if not tdecode_dist_nextrabits then
+ local t = {}
+ if NATIVE_BITOPS then
+ for i=0,29 do
+ local j = math_max(i - 2, 0)
+ t[i] = rshift(j, 1)
+ end
+ else
+ for i=0,29 do
+ local j = math_max(i - 2, 0)
+ t[i] = (j - (j % 2)) / 2
+ end
+ end
+ tdecode_dist_nextrabits = t
+ --for i=0,29 do debug('T4',i,t[i]) end
+ end
+ local dist_val = disttable:read(bs)
+ local dist_base = tdecode_dist_base[dist_val]
+ local dist_nextrabits = tdecode_dist_nextrabits[dist_val]
+ local dist_extrabits = bs:read(dist_nextrabits)
+ local dist = dist_base + dist_extrabits
+
+ --debug('BACK', len, dist)
+ for i=1,len do
+ local pos = (outstate.window_pos - 1 - dist) % 32768 + 1 -- 32K
+ output(outstate, assert(outstate.window[pos], 'invalid distance'))
+ end
+ end
+ return false
+end
+
+
+local function parse_block(bs, outstate)
+ local bfinal = bs:read(1)
+ local btype = bs:read(2)
+
+ local BTYPE_NO_COMPRESSION = 0
+ local BTYPE_FIXED_HUFFMAN = 1
+ local BTYPE_DYNAMIC_HUFFMAN = 2
+ local BTYPE_RESERVED_ = 3
+
+ if DEBUG then
+ debug('bfinal=', bfinal)
+ debug('btype=', btype)
+ end
+
+ if btype == BTYPE_NO_COMPRESSION then
+ bs:read(bs:nbits_left_in_byte())
+ local len = bs:read(16)
+ local nlen_ = noeof(bs:read(16))
+
+ for i=1,len do
+ local by = noeof(bs:read(8))
+ output(outstate, by)
+ end
+ elseif btype == BTYPE_FIXED_HUFFMAN or btype == BTYPE_DYNAMIC_HUFFMAN then
+ local littable, disttable
+ if btype == BTYPE_DYNAMIC_HUFFMAN then
+ littable, disttable = parse_huffmantables(bs)
+ else
+ littable = HuffmanTable {0,8, 144,9, 256,7, 280,8, 288,nil}
+ disttable = HuffmanTable {0,5, 32,nil}
+ end
+
+ repeat
+ local is_done = parse_compressed_item(
+ bs, outstate, littable, disttable)
+ until is_done
+ else
+ runtime_error 'unrecognized compression type'
+ end
+
+ return bfinal ~= 0
+end
+
+
+function M.inflate(t)
+ local bs = get_bitstream(t.input)
+ local outbs = get_obytestream(t.output)
+ local outstate = make_outstate(outbs)
+
+ repeat
+ local is_final = parse_block(bs, outstate)
+ until is_final
+end
+local inflate = M.inflate
+
+
+function M.gunzip(t)
+ local bs = get_bitstream(t.input)
+ local outbs = get_obytestream(t.output)
+ local disable_crc = t.disable_crc
+ if disable_crc == nil then disable_crc = false end
+
+ parse_gzip_header(bs)
+
+ local data_crc32 = 0
+
+ inflate{input=bs, output=
+ disable_crc and outbs or
+ function(byte)
+ data_crc32 = crc32(byte, data_crc32)
+ outbs(byte)
+ end
+ }
+
+ bs:read(bs:nbits_left_in_byte())
+
+ local expected_crc32 = bs:read(32)
+ local isize = bs:read(32) -- ignored
+ if DEBUG then
+ debug('crc32=', expected_crc32)
+ debug('isize=', isize)
+ end
+ if not disable_crc and data_crc32 then
+ if data_crc32 ~= expected_crc32 then
+ runtime_error('invalid compressed data--crc error')
+ end
+ end
+ if bs:read() then
+ warn 'trailing garbage ignored'
+ end
+end
+
+
+function M.adler32(byte, crc)
+ local s1 = crc % 65536
+ local s2 = (crc - s1) / 65536
+ s1 = (s1 + byte) % 65521
+ s2 = (s2 + s1) % 65521
+ return s2*65536 + s1
+end -- 65521 is the largest prime smaller than 2^16
+
+
+function M.inflate_zlib(t)
+ local bs = get_bitstream(t.input)
+ local outbs = get_obytestream(t.output)
+ local disable_crc = t.disable_crc
+ if disable_crc == nil then disable_crc = false end
+
+ local window_size_ = parse_zlib_header(bs)
+
+ local data_adler32 = 1
+
+ inflate{input=bs, output=
+ disable_crc and outbs or
+ function(byte)
+ data_adler32 = M.adler32(byte, data_adler32)
+ outbs(byte)
+ end
+ }
+
+ bs:read(bs:nbits_left_in_byte())
+
+ local b3 = bs:read(8)
+ local b2 = bs:read(8)
+ local b1 = bs:read(8)
+ local b0 = bs:read(8)
+ local expected_adler32 = ((b3*256 + b2)*256 + b1)*256 + b0
+ if DEBUG then
+ debug('alder32=', expected_adler32)
+ end
+ if not disable_crc then
+ if data_adler32 ~= expected_adler32 then
+ runtime_error('invalid compressed data--crc error')
+ end
+ end
+ if bs:read() then
+ warn 'trailing garbage ignored'
+ end
+end
+
+
+return M
\ No newline at end of file
--- /dev/null
+-- The MIT License (MIT)
+
+-- Copyright (c) 2013 DelusionalLogic
+
+-- Permission is hereby granted, free of charge, to any person obtaining a copy of
+-- this software and associated documentation files (the "Software"), to deal in
+-- the Software without restriction, including without limitation the rights to
+-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+-- the Software, and to permit persons to whom the Software is furnished to do so,
+-- subject to the following conditions:
+
+-- The above copyright notice and this permission notice shall be included in all
+-- copies or substantial portions of the Software.
+
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+-- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+-- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+-- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+local path = minetest.get_modpath(minetest.get_current_modname())
+
+local deflate = dofile(path.."/png_lua/deflatelua.lua")
+
+local requiredDeflateVersion = "0.3.20111128"
+
+if (deflate._VERSION ~= requiredDeflateVersion) then
+ error("Incorrect deflate version: must be "..requiredDeflateVersion..", not "..deflate._VERSION)
+end
+
+local function bsRight(num, pow)
+ return math.floor(num / 2^pow)
+end
+
+local function bsLeft(num, pow)
+ return math.floor(num * 2^pow)
+end
+
+local function bytesToNum(bytes)
+ local n = 0
+ for k,v in ipairs(bytes) do
+ n = bsLeft(n, 8) + v
+ end
+ if (n > 2147483647) then
+ return (n - 4294967296)
+ else
+ return n
+ end
+ n = (n > 2147483647) and (n - 4294967296) or n
+ return n
+end
+
+local function readInt(stream, bps)
+ local bytes = {}
+ bps = bps or 4
+ for i=1,bps do
+ bytes[i] = stream:read(1):byte()
+ end
+ return bytesToNum(bytes)
+end
+
+local function readChar(stream, num)
+ num = num or 1
+ return stream:read(num)
+end
+
+local function readByte(stream)
+ return stream:read(1):byte()
+end
+
+local function getDataIHDR(stream, length)
+ local data = {}
+ data["width"] = readInt(stream)
+ data["height"] = readInt(stream)
+ data["bitDepth"] = readByte(stream)
+ data["colorType"] = readByte(stream)
+ data["compression"] = readByte(stream)
+ data["filter"] = readByte(stream)
+ data["interlace"] = readByte(stream)
+ return data
+end
+
+local function getDataIDAT(stream, length, oldData)
+ local data = {}
+ if (oldData == nil) then
+ data.data = readChar(stream, length)
+ else
+ data.data = oldData.data .. readChar(stream, length)
+ end
+ return data
+end
+
+local function getDataPLTE(stream, length)
+ local data = {}
+ data["numColors"] = math.floor(length/3)
+ data["colors"] = {}
+ for i = 1, data["numColors"] do
+ data.colors[i] = {
+ R = readByte(stream),
+ G = readByte(stream),
+ B = readByte(stream)
+ }
+ end
+ return data
+end
+
+local function extractChunkData(stream)
+ local chunkData = {}
+ local length
+ local type
+ local crc
+
+ while type ~= "IEND" do
+ length = readInt(stream)
+ type = readChar(stream, 4)
+ if (type == "IHDR") then
+ chunkData[type] = getDataIHDR(stream, length)
+ elseif (type == "IDAT") then
+ chunkData[type] = getDataIDAT(stream, length, chunkData[type])
+ elseif (type == "PLTE") then
+ chunkData[type] = getDataPLTE(stream, length)
+ else
+ readChar(stream, length)
+ end
+ crc = readChar(stream, 4)
+ end
+
+ return chunkData
+end
+
+local function makePixel(stream, depth, colorType, palette)
+ local bps = math.floor(depth/8) --bits per sample
+ local pixelData = { R = 0, G = 0, B = 0, A = 0 }
+ local grey
+ local index
+ local color
+
+ if colorType == 0 then
+ grey = readInt(stream, bps)
+ pixelData.R = grey
+ pixelData.G = grey
+ pixelData.B = grey
+ pixelData.A = 255
+ elseif colorType == 2 then
+ pixelData.R = readInt(stream, bps)
+ pixelData.G = readInt(stream, bps)
+ pixelData.B = readInt(stream, bps)
+ pixelData.A = 255
+ elseif colorType == 3 then
+ index = readInt(stream, bps)+1
+ color = palette.colors[index]
+ pixelData.R = color.R
+ pixelData.G = color.G
+ pixelData.B = color.B
+ pixelData.A = 255
+ elseif colorType == 4 then
+ grey = readInt(stream, bps)
+ pixelData.R = grey
+ pixelData.G = grey
+ pixelData.B = grey
+ pixelData.A = readInt(stream, bps)
+ elseif colorType == 6 then
+ pixelData.R = readInt(stream, bps)
+ pixelData.G = readInt(stream, bps)
+ pixelData.B = readInt(stream, bps)
+ pixelData.A = readInt(stream, bps)
+ end
+
+ return pixelData
+end
+
+local function bitFromColorType(colorType)
+ if colorType == 0 then return 1 end
+ if colorType == 2 then return 3 end
+ if colorType == 3 then return 1 end
+ if colorType == 4 then return 2 end
+ if colorType == 6 then return 4 end
+ error 'Invalid colortype'
+end
+
+local function paethPredict(a, b, c)
+ local p = a + b - c
+ local varA = math.abs(p - a)
+ local varB = math.abs(p - b)
+ local varC = math.abs(p - c)
+
+ if varA <= varB and varA <= varC then
+ return a
+ elseif varB <= varC then
+ return b
+ else
+ return c
+ end
+end
+
+local function filterType1(curPixel, lastPixel)
+ local lastByte
+ local newPixel = {}
+ for fieldName, curByte in pairs(curPixel) do
+ lastByte = lastPixel and lastPixel[fieldName] or 0
+ newPixel[fieldName] = (curByte + lastByte) % 256
+ end
+ return newPixel
+end
+
+local prevPixelRow = {}
+local function getPixelRow(stream, depth, colorType, palette, length)
+ local pixelRow = {}
+ local bpp = math.floor(depth/8) * bitFromColorType(colorType)
+ local bpl = bpp*length
+ local filterType = readByte(stream)
+
+ if filterType == 0 then
+ for x = 1, length do
+ pixelRow[x] = makePixel(stream, depth, colorType, palette)
+ end
+ elseif filterType == 1 then
+ local curPixel
+ local lastPixel
+ local newPixel
+ local lastByte
+ for x = 1, length do
+ curPixel = makePixel(stream, depth, colorType, palette)
+ lastPixel = prevPixelRow[pixelNum]
+ newPixel = {}
+ for fieldName, curByte in pairs(curPixel) do
+ lastByte = lastPixel and lastPixel[fieldName] or 0
+ newPixel[fieldName] = (curByte + lastByte) % 256
+ end
+ pixelRow[x] = newPixel
+ end
+ else
+ error("Unsupported filter type: " .. tostring(filterType))
+ end
+ prevPixelRow = pixelRow
+
+ return pixelRow
+end
+
+
+local function pngImage(path, progCallback, verbose, memSave)
+ local stream = io.open(path, "rb")
+ local chunkData
+ local imStr
+ local width = 0
+ local height = 0
+ local depth = 0
+ local colorType = 0
+ local output = {}
+ local pixels = {}
+ local StringStream
+ local function printV(msg)
+ if (verbose) then
+ print(msg)
+ end
+ end
+
+ if readChar(stream, 8) ~= "\137\080\078\071\013\010\026\010" then
+ error "Not a png"
+ end
+
+ printV("Parsing Chunks...")
+ chunkData = extractChunkData(stream)
+
+ width = chunkData.IHDR.width
+ height = chunkData.IHDR.height
+ depth = chunkData.IHDR.bitDepth
+ colorType = chunkData.IHDR.colorType
+
+ printV("Deflating...")
+ deflate.inflate_zlib {
+ input = chunkData.IDAT.data,
+ output = function(byte)
+ output[#output+1] = string.char(byte)
+ end,
+ disable_crc = true
+ }
+ StringStream = {
+ str = table.concat(output),
+ read = function(self, num)
+ local toreturn = self.str:sub(1, num)
+ self.str = self.str:sub(num + 1, self.str:len())
+ return toreturn
+ end
+ }
+
+ printV("Creating pixelmap...")
+ for i = 1, height do
+ local pixelRow = getPixelRow(StringStream, depth, colorType, chunkData.PLTE, width)
+ if progCallback ~= nil then
+ progCallback(i, height, pixelRow)
+ end
+ if not memSave then
+ pixels[i] = pixelRow
+ end
+ end
+
+ printV("Done.")
+ return {
+ width = width,
+ height = height,
+ depth = depth,
+ colorType = colorType,
+ pixels = pixels
+ }
+end
+
+return pngImage
\ No newline at end of file