summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/l-gzip.lua
blob: 31466bde8f47654a995a4907af890be40685d117 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
if not modules then modules = { } end modules ['l-gzip'] = {
    version   = 1.001,
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

if gzip then

    local suffix, suffixes = file.suffix, file.suffixes

    function gzip.load(filename)
        local f = io.open(filename,"rb")
        if not f then
            -- invalid file
        elseif suffix(filename) == "gz" then
            f:close()
            local g = gzip.open(filename,"rb")
            if g then
                local str = g:read("*all")
                g:close()
                return str
            end
        else
            local str = f:read("*all")
            f:close()
            return str
        end
    end

    function gzip.save(filename,data)
        if suffix(filename) ~= "gz" then
            filename = filename .. ".gz"
        end
        local f = io.open(filename,"wb")
        if f then
            local s = zlib.compress(data or "",9,nil,15+16)
            f:write(s)
            f:close()
            return #s
        end
    end

    function gzip.suffix(filename)
        local suffix, extra = suffixes(filename)
        local gzipped = extra == "gz"
        return suffix, gzipped
    end

else

    -- todo: fallback on flate

end

if flate then

    local type = type
    local find = string.find

    local compress   = flate.gz_compress
    local decompress = flate.gz_decompress

    local absmax     = 128*1024*1024
    local initial    =       64*1024
    local identifier = "^\x1F\x8B\x08"

    function gzip.compressed(s)
        return s and find(s,identifier)
    end

    function gzip.compress(s,level)
        if s and not find(s,identifier) then -- the find check might go away
            if not level then
                level = 3
            elseif level <= 0 then
                return s
            elseif level > 9 then
                level = 9
            end
            return compress(s,level) or s
        end
    end

    function gzip.decompress(s,size,iterate)
        if s and find(s,identifier) then
            if type(size) ~= "number" then
                size = initial
            end
            if size > absmax then
                size = absmax
            end
            if type(iterate) == "number" then
                max = size * iterate
            elseif iterate == nil or iterate == true then
                iterate = true
                max     = absmax
            end
            if max > absmax then
                max = absmax
            end
            while true do
                local d = decompress(s,size)
                if d then
                    return d
                end
                size = 2 * size
                if not iterate or size > max then
                    return false
                end
            end
        else
            return s
        end
    end

end