0
|
1 // Written in the D programming language
|
|
2 // www.digitalmars.com/d/
|
|
3
|
|
4 /// wraps zlib
|
|
5 module dynamin.lodepng.zlib_codec;
|
|
6 pragma(lib, "zlib");
|
|
7
|
|
8 version (Tango)
|
|
9 {
|
|
10 import czlib = tango.io.compress.c.zlib;
|
|
11 }
|
|
12 else
|
|
13 {
|
|
14 import czlib = etc.c.zlib;
|
|
15 }
|
|
16
|
|
17 import dynamin.lodepng.util;
|
|
18
|
|
19
|
|
20 // buffered decompression of zlib streams, avoiding GC provocation where possible
|
|
21 struct DecodeStream
|
|
22 {
|
|
23 // TODO: should be scope class for releasing zlib resources on scope exit
|
|
24
|
|
25 // constructor: initialize with target, will be resized as needed
|
|
26 static DecodeStream create(ref ubyte[] dest)
|
|
27 {
|
|
28 DecodeStream result;
|
|
29 result.dest = dest;
|
|
30
|
|
31 result.zlibStream.next_out = dest.ptr;
|
|
32 result.zlibStream.avail_out = dest.length;
|
|
33 result.zlibStream.avail_out = dest.length; //Z_BINARY
|
|
34 result.zlibStream.data_type = czlib.Z_BINARY;
|
|
35
|
|
36 return result;
|
|
37 }
|
|
38
|
|
39 ubyte[] opCall()
|
|
40 {
|
|
41 return dest;
|
|
42 }
|
|
43
|
|
44 void opCall(in ubyte[] input)
|
|
45 {
|
|
46 zlibStream.next_in = input.ptr;
|
|
47 zlibStream.avail_in = input.length;
|
|
48
|
|
49 if (!isInit)
|
|
50 {
|
|
51 isInit = true;
|
|
52 msg = czlib.inflateInit(&zlibStream);
|
|
53 if (msg)
|
|
54 {
|
|
55 czlib.inflateEnd(&zlibStream);
|
|
56 throw new Exception("");// TODO: toString(msg));
|
|
57 }
|
|
58 }
|
|
59
|
|
60 while(zlibStream.avail_in)
|
|
61 {
|
|
62 msg = czlib.inflate(&zlibStream, czlib.Z_NO_FLUSH);
|
|
63
|
|
64 if (msg == czlib.Z_STREAM_END)
|
|
65 {
|
|
66 czlib.inflateEnd(&zlibStream);
|
|
67 hasEnded = true;
|
|
68 dest.length = zlibStream.total_out;
|
|
69 return;
|
|
70 }
|
|
71 else if (msg != czlib.Z_OK)
|
|
72 {
|
|
73 czlib.inflateEnd(&zlibStream);
|
|
74 throw new Exception("");// TODO: toString(zlibStream.msg));
|
|
75 }
|
|
76 else if(zlibStream.avail_out == 0)
|
|
77 {
|
|
78 dest.length = dest.length * 2;
|
|
79 zlibStream.next_out = &dest[dest.length / 2];
|
|
80 zlibStream.avail_out = dest.length / 2;
|
|
81 }
|
|
82 }
|
|
83 }
|
|
84
|
|
85 bool isInit = false;
|
|
86 bool hasEnded = false;
|
|
87
|
|
88 private
|
|
89 {
|
|
90 ubyte[] dest;
|
|
91 int msg = 0;
|
|
92 czlib.z_stream zlibStream;
|
|
93 }
|
|
94 }
|
|
95
|
|
96 struct Encoder
|
|
97 {
|
|
98 static Encoder create(ubyte strategy = czlib.Z_RLE, uint clevel = 9)
|
|
99 {
|
|
100 Encoder result;
|
|
101 result.level = clevel;
|
|
102 result.strategy = strategy;
|
|
103 return result;
|
|
104 }
|
|
105 ubyte[] opCall(in ubyte[] source)
|
|
106 {
|
|
107 ubyte[] result;
|
|
108 return this.opCall(source, result);
|
|
109
|
|
110 }
|
|
111 ubyte[] opCall(in ubyte[] source, ref ubyte[] buffer)
|
|
112 {
|
|
113 if (source.length == 0)
|
|
114 {
|
|
115 buffer.length = 0;
|
|
116 return buffer;
|
|
117 }
|
|
118
|
|
119 buffer.length = source.length / 4;
|
|
120 czlib.z_stream stream;
|
|
121 stream.next_in = source.ptr;
|
|
122 stream.avail_in = source.length;
|
|
123 stream.next_out = buffer.ptr;
|
|
124 stream.avail_out = buffer.length;
|
|
125 stream.data_type = czlib.Z_BINARY;
|
|
126
|
|
127 czlib.deflateInit2(&stream, 9, czlib.Z_DEFLATED, 15, level, strategy);
|
|
128 auto msg = czlib.deflate(&stream, czlib.Z_FINISH);
|
|
129 while(msg != czlib.Z_STREAM_END)
|
|
130 {
|
|
131 buffer.length = buffer.length + buffer.length;
|
|
132 stream.next_out = &buffer[buffer.length / 2];
|
|
133 stream.avail_out = buffer.length / 2;
|
|
134 msg = czlib.deflate(&stream, czlib.Z_FINISH);
|
|
135 }
|
|
136
|
|
137 assert(msg == czlib.Z_STREAM_END);
|
|
138 buffer.length = stream.total_out;
|
|
139 czlib.deflateEnd(&stream);
|
|
140
|
|
141 return buffer;
|
|
142 }
|
|
143
|
|
144 private ubyte strategy = czlib.Z_RLE;
|
|
145 private ubyte level = 9;
|
|
146 }
|