1%%% Utility functions for zlib.
2-module(yaws_zlib).
3-author('carsten@codimi.de').
4
5
6-include("../include/yaws.hrl").
7
8
9-export([gzipInit/1, gzipInit/2, gzipEnd/1, gzipDeflate/4, gzip/1, gzip/2]).
10
11
12gzipInit(Z) ->
13    gzipInit(Z, #deflate{}).
14
15gzipInit(Z, DOpts) ->
16    ok = zlib:deflateInit(Z, DOpts#deflate.compression_level, deflated,
17                          DOpts#deflate.window_size, DOpts#deflate.mem_level,
18                          DOpts#deflate.strategy),
19    undefined.
20
21
22gzipEnd(Z) ->
23    zlib:deflateEnd(Z).
24
25
26gzipDeflate(Z, undefined, Bin, Flush) ->
27    Crc32 = zlib:crc32(Z),
28    Head = <<
29                                                % ID
30             16#1f, 16#8b,
31                                                % deflate
32             8:8,
33                                                % flags
34             0:8,
35                                                % mtime
36             0:32,
37                                                % xflags
38             0:8,
39                                                % OS_UNKNOWN
40                                                % Set to Unix instead?
41             255:8>>,
42    {ok, Priv, Bs} = gzipDeflate(Z, {Crc32,0}, Bin, Flush),
43    {ok, Priv, [Head | Bs]};
44
45gzipDeflate(Z, {Crc32,Size}, Bin, Flush) ->
46    Bs = zlib:deflate(Z, Bin, Flush),
47    Crc1 = zlib:crc32(Z, Crc32, Bin),
48    Size1 = Size+size(Bin),
49    Data =
50        if
51            Flush == finish ->
52                                                % Appending should not
53                                                % hurt, so let's be a
54                                                % bit more consistent
55                                                % here.
56                Bs ++ [<<Crc1:32/little, Size1:32/little>>];
57            true ->
58                Bs
59        end,
60    {ok, {Crc1, Size1}, Data}.
61
62
63%% like zlib:gzip/1, but returns an io list
64gzip(Data) ->
65    gzip(Data, #deflate{}).
66
67gzip(Data, DOpts) when is_binary(Data) ->
68    Z = zlib:open(),
69    {ok, _, D} = gzipDeflate(Z, gzipInit(Z, DOpts), Data, finish),
70    gzipEnd(Z),
71    zlib:close(Z),
72    {ok, D};
73
74gzip(Data, DOpts) ->
75    Z = zlib:open(),
76    gzip_loop(Z, gzipInit(Z, DOpts), Data, [], []).
77
78gzip_loop(Z, P, [], [], A) ->
79    {ok, _, D} = gzipDeflate(Z, P, <<>>, finish),
80    gzipEnd(Z),
81    zlib:close(Z),
82    {ok, [A|D]};
83gzip_loop(Z, P, B, C, A) when is_binary(B) ->
84    {ok, P1, D} = gzipDeflate(Z, P, B, none),
85    gzip_loop(Z, P1, C, [],
86              case D of
87                  [] -> A;
88                  _ ->
89                      case A of
90                          [] -> D;
91                          _ -> [A|D]
92                      end
93              end);
94gzip_loop(Z, P, [I|T], C, A) when is_integer(I) ->
95    gzip_loop(Z, P, list_to_binary([I|T]), C, A);
96gzip_loop(Z, P, [H], C, A) ->
97    gzip_loop(Z, P, H, C, A);
98gzip_loop(Z, P, [H|T], C, A) ->
99    gzip_loop(Z, P, H, [T|C], A);
100gzip_loop(Z, P, [], C, A) ->
101    gzip_loop(Z, P, C, [], A);
102gzip_loop(Z, P, I, C, A) when is_integer(I) ->
103    gzip_loop(Z, P, <<I>>, C, A).
104