Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

CompressionPackageDesign: tango-archive-stuff.d

File tango-archive-stuff.d, 5.2 kB (added by DRK, 1 year ago)

Some thoughts on archive model design

Line 
1 module compression;
2
3 /**
4  * tango.compression.model.ICompressionCodec
5  */
6
7 import tango.io.model.IConduit;
8 import tango.io.protocol.model.IReader;
9 import tango.io.protocol.model.IWriter;
10
11 /**
12  * CompressionProfile provides an abstract way of setting up compression
13  * settings without having to worry about the concrete details.
14  */
15 enum CompressionProfile
16 {
17     Normal = 1, /// Average level compression.
18     Fast = 0,   /// As fast as possible: may omit compression altogether.
19     Small = 2   /// As small as possible.
20 }
21
22 interface ICompressionCodec : IConduitFilter
23 {
24     /**
25      * These two functions provide a way to serialise the codec state
26      * necessary to exactly reproduce its behaviour.  For instance, this could
27      * be used to write out the precise profile used to compress a stream of
28      * data, thus allowing it to be decompressed again.
29      */
30     abstract void readProfile(IReader input);
31     abstract void writeProfile(IWriter output); /// ditto
32
33     /**
34      * These two functions access the abstract profile setting, which means
35      * people don't have to stuff around with the above two if they don't have
36      * the need.
37      */
38     abstract CompressionProfile getProfile();
39     abstract void setProfile(CompressionProfile profile); /// ditto
40 }
41
42 /**
43  * tango.compression.ZLib
44  */
45
46 //import tango.io.model.IConduit : IConduitFilter;
47 //import tango.compression.model.ICompressionCodec;
48
49 class ZLib : ICompressionCodec
50 {
51     protected IConduitFilter next;
52
53     private
54     {
55         CompressionProfile profile_;
56         int level_; // = ???  There's a default constant somewhere...
57         z_stream zs;
58         bool inited = false;
59     }
60
61     this()
62     {
63         this(CompressionProfile.init);
64     }
65
66     this(CompressionProfile profile)
67     {
68         this.profile = profile;
69     }
70
71     this(int level)
72     {
73         this.level = level;
74     }
75
76     uint reader(void[] dst)
77     {
78     }
79
80     uint writer(void[] src)
81     {
82         if( src.length == 0 )
83             // You never know what weird stuff people will do :p
84             return next.writer(src);
85
86         if( !inited )
87             initZlib();
88
89         // Create a new buffer for the compressed data to live in, and tell
90         // zlib where it is.  Also important is to make sure that the buffer
91         // is deleted once we leave this function.
92         ubyte[] destbuf = new ubyte[zs.avail_in + src.length];
93         scope(exit) delete destbuf;
94         zs.next_out = destbuf.ptr;
95         zs.avail_out = destbuf.length;
96
97         if( zs.avail_in )
98             // If there is already some data ready to be compressed, then we
99             // need to prepend that to our source data.
100             src = zs.next_in[0 .. zs.avail_in] ~ src;
101
102         // Tell zlib where the input data lives.
103         zs.next_in = src.ptr;
104         zs.avail_in = src.length;
105
106         // Ok, compress that data; compress it good.
107         auto err = deflate(&zs, Z_NO_FLUSH);
108         if( err != Z_STREAM_END && err != Z_OK )
109             // Uh-oh; something went horribly, horribly wrong.
110             zerror(err);
111
112         // We truncate the output buffer since zlib may not have used all the
113         // space we allocated; zs.avail_out is the number of bytes it didn't
114         // use.
115         destbuf = destbuf[0 .. $-zs.avail_out]
116         destbuf.length = destbuf.length - zs.avail_out;
117
118         // Ok; our original data is now compressed.  We just need to feed that
119         // to the next filter in the chain.
120         return next.writer(destbuf);
121     }
122
123     int level()
124     {
125         return level_;
126     }
127
128     int level(int level_)
129     {
130         if( inited )
131             throw new Exception("Cannot change compression settings"
132                     " after (de)compression has begun!");
133         this.level_ = level_;
134         return level_;
135     }
136
137     CompressionProfile profile()
138     {
139         return profile_;
140     }
141
142     CompressionProfile profile(CompressionProfile profile_)
143     {
144         switch( profile_ )
145         {
146             /+case CompressionProfile.None:
147                 level = Z_NO_COMPRESSION;
148                 break;+/
149
150             case CompressionProfile.Fast:
151                 level = Z_BEST_SPEED;
152                 break;
153
154             case CompressionProfile.Normal:
155                 level = Z_DEFAULT_COMPRESSION;
156                 break;
157
158             case CompressionProfile.Small:
159                 level = Z_BEST_COMPRESSION;
160                 break;
161
162             default:
163                 throw new Exception("Invalid compression profile.");
164         }
165
166         return profile_;
167     }
168
169     void readProfile(IReader input)
170     {
171         if( inited )
172             throw new Exception("Cannot change compression settings"
173                     " after (de)compression has begun!");
174
175         int level_;
176        
177         input.get (level_);
178         level = level_;
179     }
180
181     void writeProfile(IWriter output)
182     {
183         output.put (level);
184     }
185
186     void bind(IConduit conduit, IConduitFilter next)
187     {
188         this.next = next;
189     }
190
191     void unbind()
192     {
193     }
194
195     private void initZlib()
196     {
197         //
198     }
199 }