Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 102 lines (84 sloc) 2.929 kb
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
%%% Utility functions for zlib.
-module(yaws_zlib).
-author('carsten@codimi.de').

-export([gzipInit/1, gzipEnd/1, gzipDeflate/4, gzip/1]).


gzipInit(Z) ->
    ok = zlib:deflateInit(Z, default, deflated, -15, 8, default),
    undefined.


gzipEnd(Z) ->
    zlib:deflateEnd(Z).


gzipDeflate(Z, undefined, Bin, Flush) ->
    Crc32 = zlib:crc32(Z),
    Head = <<
                                                % ID
             16#1f, 16#8b,
                                                % deflate
             8:8,
                                                % flags
             0:8,
                                                % mtime
             0:32,
                                                % xflags
             0:8,
                                                % OS_UNKNOWN
                                                % Set to Unix instead?
             255:8>>,
    {ok, Priv, Bs} = gzipDeflate(Z, {Crc32,0}, Bin, Flush),
    {ok, Priv, [Head | Bs]};

gzipDeflate(Z, {Crc32,Size}, Bin, Flush) ->
    Bs = zlib:deflate(Z, Bin, Flush),
    {ok, Crc1} = crc32(Z, Crc32, Bin),
    Size1 = Size+size(Bin),
    Data =
        if
            Flush == finish ->
                                                % Appending should not
                                                % hurt, so let's be a
                                                % bit more consistent
                                                % here.
                Bs ++ [<<Crc1:32/little, Size1:32/little>>];
            true ->
                Bs
        end,
    {ok, {Crc1, Size1}, Data}.


%% like zlib:gzip/1, but returns an io list

gzip(Data) when is_binary(Data) ->
    Z = zlib:open(),
    {ok, _, D} = gzipDeflate(Z, gzipInit(Z), Data, finish),
    gzipEnd(Z),
    zlib:close(Z),
    {ok, D};

gzip(Data) ->
    Z = zlib:open(),
    gzip_loop(Z, gzipInit(Z), Data, [], []).

gzip_loop(Z, P, [], [], A) ->
    {ok, _, D} = gzipDeflate(Z, P, <<>>, finish),
    gzipEnd(Z),
    zlib:close(Z),
    {ok, [A|D]};
gzip_loop(Z, P, B, C, A) when is_binary(B) ->
    {ok, P1, D} = gzipDeflate(Z, P, B, none),
    gzip_loop(Z, P1, C, [],
              case D of
                  [] -> A;
                  _ ->
                      case A of
                          [] -> D;
                          _ -> [A|D]
                      end
              end);
gzip_loop(Z, P, [I|T], C, A) when is_integer(I) ->
    gzip_loop(Z, P, list_to_binary([I|T]), C, A);
gzip_loop(Z, P, [H], C, A) ->
    gzip_loop(Z, P, H, C, A);
gzip_loop(Z, P, [H|T], C, A) ->
    gzip_loop(Z, P, H, [T|C], A);
gzip_loop(Z, P, [], C, A) ->
    gzip_loop(Z, P, C, [], A);
gzip_loop(Z, P, I, C, A) when is_integer(I) ->
    gzip_loop(Z, P, <<I>>, C, A).


%% To work around a bug in zlib.

crc32(Z, CRC, Binary) ->
    case port_control(Z, 17, <<CRC:32, Binary/binary>>) of
        [2,A,B,C,D] -> {ok, (A bsl 24)+(B bsl 16)+(C bsl 8)+D}
    end.

Something went wrong with that request. Please try again.