OSDN Git Service

Implement package installer for tar archives.
[mingw/mingw-get.git] / src / pkgstrm.cpp
1 /*
2  * pkgstrm.cpp
3  *
4  * $Id$
5  *
6  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7  * Copyright (C) 2009, 2010, MinGW Project
8  *
9  *
10  * Implementation of the streaming data filters, which will be used
11  * for reading package archives in any supported compression format;
12  * currently supported formats are:--
13  *
14  *   raw    (uncompressed)
15  *   gzip   (compressed)
16  *   bzip2  (compressed)
17  *   lzma   (compressed)
18  *   xz     (compressed)
19  *
20  *
21  * This is free software.  Permission is granted to copy, modify and
22  * redistribute this software, under the provisions of the GNU General
23  * Public License, Version 3, (or, at your option, any later version),
24  * as published by the Free Software Foundation; see the file COPYING
25  * for licensing details.
26  *
27  * Note, in particular, that this software is provided "as is", in the
28  * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
29  * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
30  * PARTICULAR PURPOSE.  Under no circumstances will the author, or the
31  * MinGW Project, accept liability for any damages, however caused,
32  * arising from the use of this software.
33  *
34  */
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #ifndef O_BINARY
39 /*
40  * MS-Windows nuisances...
41  * Files are expected to be either explicitly text or binary;
42  * (UNIX makes no such specific distinction).  We want to force
43  * treatment of all files as binary; define a "no-op" substitute
44  * for the appropriate MS-Windows attribute, for when we compile
45  * on UNIX, so we may henceforth just use it unconditionally.
46  */
47 # ifdef _O_BINARY
48 #  define O_BINARY _O_BINARY
49 # else
50 #  define O_BINARY  0
51 # endif
52 #endif
53
54 /* We need to enable PKGSTRM_H_SPECIAL awareness, when we compile this...
55  */
56 #define  PKGSTRM_H_SPECIAL  1
57 #include "pkgstrm.h"
58
59 /*****
60  *
61  * Class Implementation: pkgArchiveStream
62  *
63  * This class uses a default constructor and default virtual destructor.
64  * We never instantiate objects of this class directly; all derived classes
65  * provide their own specialised constructors and destructors, together with
66  * a mandatory specialised "Read" method.
67  *
68  * We do, however, provide one generic "GetRawData" method, which derived
69  * classes may adopt, or may override, as necessary...
70  *
71  */
72 int pkgArchiveStream::GetRawData( int fd, uint8_t *buf, size_t max )
73 {
74   /* Generic helper function for reading a compressed data stream into
75    * its decompressing filter's input buffer.  The default implementation
76    * assumes a file stream, and simply invokes a read() request; however,
77    * we segregate this function, to facilitate an override to handle
78    * other input streaming capabilities.
79    */
80   return read( fd, buf, max );
81 }
82
83 /*****
84  *
85  * Class Implementation: pkgRawArchiveStream
86  *
87  * This is the simplest archive stream class, suitable for archives
88  * which have been stored WITHOUT compression...
89  *
90  */
91 pkgRawArchiveStream::pkgRawArchiveStream( const char *filename )
92 {
93   /* The constructor has little to to, but to open the archive file
94    * and associate a file descriptor with the resultant data stream.
95    */
96   fd = open( filename, O_RDONLY | O_BINARY );
97 }
98
99 pkgRawArchiveStream::~pkgRawArchiveStream()
100 {
101   /* The destructor needs only to close the data stream.
102    */
103   close( fd );
104 }
105
106 int pkgRawArchiveStream::Read( char *buf, size_t max )
107 {
108   /* While the stream reader simply transfers the requested number
109    * of bytes from the stream, to the caller's buffer.
110    */
111   return read( fd, buf, max );
112 }
113
114 /*****
115  *
116  * Class Implementation: pkgGzipArchiveStream
117  *
118  * This class creates an input streaming interface, suitable for
119  * reading archives which have been stored with gzip compression.
120  * The implementation is based on the use of libz.a, which allows
121  * for a similar implementation to that of pkgRawArchiveStream.
122  *
123  */
124 pkgGzipArchiveStream::pkgGzipArchiveStream( const char *filename )
125 {
126   /* Once more, the constructor has little to do but open the stream;
127    * in this case, the method is analogous to C's fopen().
128    */
129   stream = gzopen( filename, "rb" );
130 }
131
132 pkgGzipArchiveStream::~pkgGzipArchiveStream()
133 {
134   /* Another destructor, with little to do but close the stream; the
135    * gzclose() call suffices for the purpose.
136    */
137   gzclose( stream );
138 }
139
140 int pkgGzipArchiveStream::Read( char *buf, size_t max )
141 {
142   /* The reader is again served by a single function call, to transfer
143    * the requested volume of decompressed data from the raw input file
144    * to the caller's buffer.
145    */
146   return gzread( stream, buf, max );
147 }
148
149 /*****
150  *
151  * Class Implementation: pkgBzipArchiveStream
152  *
153  * This class creates an input streaming interface, suitable for
154  * reading archives which have been stored with bzip2 compression.
155  * The implementation is based on the use of libbz2.a, which again
156  * allows for a fairly simple implementation, which is also quite
157  * analogous to that of pkgRawArchiveStream.
158  *
159  */
160 pkgBzipArchiveStream::pkgBzipArchiveStream( const char *filename )
161 {
162   /* The constructor carries a marginal additional overhead, in
163    * that it must first open a regular file, before associating
164    * a bzip2 control structure with it; subsequent stream access
165    * is directed exclusively through that control structure.
166    */
167   FILE *streamfile = fopen( filename, "rb" );
168   stream = BZ2_bzReadOpen( &bzerror, streamfile, 0, 0, 0, 0 );
169 }
170
171 pkgBzipArchiveStream::~pkgBzipArchiveStream()
172 {
173   /* For the destructor, it is again just a matter of closing
174    * the bzip2 stream; (this also takes care of closing the
175    * associated file stream).
176    */
177   BZ2_bzReadClose( &bzerror, stream );
178 }
179
180 int pkgBzipArchiveStream::Read( char *buf, size_t max )
181 {
182   /* Once again, reading is a simple matter of transferring
183    * the requisite number of bytes to the caller's buffer.
184    */
185   return BZ2_bzRead( &bzerror, stream, buf, max );
186 }
187
188 /*****
189  *
190  * Class Implementation: pkgLzmaArchiveStream
191  *
192  * This class creates an input streaming interface, suitable for
193  * reading archives which have been stored with lzma compression;
194  * based on the use of liblzma.a, this implements an adaptation of
195  * Lasse Collin's "xzdec" code, as configured for use as an lzma
196  * decompressor.
197  *
198  */
199 static inline
200 uint64_t memlimit()
201 {
202   /* Naively cap the memory available to lzma and xz decoders.
203    *
204    * FIXME: libarchive appears to use this; however, Lasse Collin
205    * provides a more sophisticated method for xz, based on actual
206    * physical memory footprint; we should adopt it.
207    */
208   return 1ULL << 23 + 1ULL << 21;
209 }
210
211 static
212 void lzma_stream_initialise( lzma_stream *stream )
213 {
214   /* This simple helper provides a static template, which is
215    * used to define initial state for lzma and xz decoders.
216    */
217   static const lzma_stream stream_template = LZMA_STREAM_INIT;
218   *stream = stream_template;
219   /*
220    * ...mark the input buffer as initially empty.
221    */
222   stream->avail_in = 0;
223 }
224
225 pkgLzmaArchiveStream::pkgLzmaArchiveStream( const char *filename )
226 {
227   /* The constructor must first open a file stream...
228    */
229   if( (fd = open( filename, O_RDONLY | O_BINARY )) >= 0 )
230   {
231     /* ...then set up the lzma decoder, in appropriately
232      * initialised state...
233      */
234     lzma_stream_initialise( &stream );
235     status = lzma_alone_decoder( &stream, memlimit() );
236   }
237 }
238
239 pkgLzmaArchiveStream::pkgLzmaArchiveStream( int fileno ):fd( fileno )
240 {
241   /* ...then set up the lzma decoder, in appropriately
242    * initialised state...
243    */
244   if( fd != -1 )
245   {
246     lzma_stream_initialise( &stream );
247     status = lzma_alone_decoder( &stream, memlimit() );
248   }
249 }
250
251 pkgLzmaArchiveStream::~pkgLzmaArchiveStream()
252 {
253   /* The destructor frees memory resources allocated to the decoder,
254    * and closes the input stream file descriptor.
255    *
256    * FIXME: The lzma_alone_decoder may indicate end-of-stream, before
257    * the physical input data stream is exhausted.  For now, we silently
258    * ignore any such residual data; (it is likely to be garbage anyway).
259    * Should we handle it any more explicitly?
260    */
261   if( fd != -1 )
262   {
263     lzma_end( &stream );
264     close( fd );
265   }
266 }
267
268 int pkgLzmaArchiveStream::Read( char *buf, size_t max )
269 {
270   /* Read an lzma compressed data stream; store up to "max" bytes of
271    * decompressed data into "buf".
272    */
273   if( fd == -1 )
274     /*
275      * We cannot read from a stream with an invalid descriptor;
276      * in this circumstance, just say "nothing was read"...
277      */
278     return fd;
279
280   /* Otherwise the stream is ready to read...
281    * Start by directing the decoder to use "buf", initially marking it 
282    * as "empty".
283    */
284   stream.next_out = (uint8_t *)(buf);
285   stream.avail_out = max;
286
287   while( (stream.avail_out > 0) && (status == LZMA_OK) )
288   {
289     /* "buf" hasn't been filled yet, and the decoder continues to say
290      * that more data may be available.
291      */
292     if( stream.avail_in == 0 )
293     {
294       /* We exhausted the current content of the raw input buffer;
295        * top it up again.
296        */
297       stream.next_in = streambuf;
298       if( (stream.avail_in = GetRawData( fd, streambuf, BUFSIZ )) < 0 )
299       {
300         /* FIXME: an I/O error occurred here: need to handle it!!!
301          */
302       }
303     }
304
305     /* Run the decoder, to decompress as much as possible of the data
306      * currently in the raw input buffer, filling available space in
307      * "buf"; go round again, in case we exhausted the raw input data
308      * before we ran out of available space in "buf".
309      */
310     status = lzma_code( &stream, LZMA_RUN );
311   }
312
313   /* When we get to here, we either filled "buf" completely, or we
314    * completely exhausted the raw input stream; in either case, we
315    * return the actual number of bytes stored in "buf", (i.e. its
316    * total size, less any residual free space).
317    */
318   return max - stream.avail_out;
319 }
320
321 /*****
322  *
323  * Class Implementation: pkgXzArchiveStream
324  *
325  * This class creates an input streaming interface, suitable for
326  * reading archives which have been stored with xz compression;
327  * again based on the use of liblzma.a, this implements a further
328  * adaptation of Lasse Collin's "xzdec" code, as configured for
329  * use as an xz decompressor.
330  *
331  */
332 pkgXzArchiveStream::pkgXzArchiveStream( const char *filename )
333 {
334   /* The constructor must first open a file stream...
335    */
336   if( (fd = open( filename, O_RDONLY | O_BINARY )) >= 0 )
337   {
338     /* ...then set up the lzma decoder, in appropriately
339      * initialised state...
340      */
341     lzma_stream_initialise( &stream );
342     status = lzma_stream_decoder( &stream, memlimit(), LZMA_CONCATENATED );
343
344     /* Finally, recognising that with LZMA_CONCATENATED data,
345      * we will eventually need to switch the decoder from its
346      * initial LZMA_RUN state to LZMA_FINISH, we must provide
347      * a variable to specify the active state, (which we may
348      * initialise for the LZMA_RUN state).
349      */
350     opmode = LZMA_RUN;
351   }
352 }
353
354 pkgXzArchiveStream::~pkgXzArchiveStream()
355 {
356   /* This destructor frees memory resources allocated to the decoder,
357    * and closes the input stream file descriptor; unlike the preceding
358    * case of the lzma_alone_decoder, the lzma_stream_decoder guarantees
359    * that there is no trailing garbage remaining from the input stream.
360    */
361   if( fd != -1 )
362   {
363     lzma_end( &stream );
364     close( fd );
365   }
366 }
367
368 int pkgXzArchiveStream::Read( char *buf, size_t max )
369 {
370   /* Read an xz compressed data stream; store up to "max" bytes of
371    * decompressed data into "buf".
372    */
373   if( fd == -1 )
374     /*
375      * We cannot read from a stream with an invalid descriptor;
376      * in this circumstance, just say "nothing was read"...
377      */
378     return fd;
379
380   /* Otherwise the stream is ready to read...
381    * Start by directing the decoder to use "buf", initially marking it 
382    * as "empty".
383    */
384   stream.next_out = (uint8_t *)(buf);
385   stream.avail_out = max;
386
387   while( (stream.avail_out > 0) && (status == LZMA_OK) )
388   {
389     /* "buf" hasn't been filled yet, and the decoder continues to say
390      * that more data may be available.
391      */
392     if( stream.avail_in == 0 )
393     {
394       /* We exhausted the current content of the raw input buffer;
395        * top it up again.
396        */
397       stream.next_in = streambuf;
398       if( (stream.avail_in = GetRawData( fd, streambuf, BUFSIZ )) < 0 )
399       {
400         /* FIXME: an I/O error occurred here: need to handle it!!!
401          */
402       }
403
404       else if( stream.avail_in < BUFSIZ )
405       {
406         /* A short read indicates end-of-input...
407          * Unlike the case of the lzma_alone_decoder, (as used for
408          * decompressing lzma streams), the lzma_stream_decoder, (when
409          * initialised for LZMA_CONCATENATED data, as we use here), may
410          * run lzma_code in either LZMA_RUN or LZMA_FINISH mode; the
411          * normal mode is LZMA_RUN, but we switch to LZMA_FINISH
412          * when we have exhausted the input stream.
413          */
414         opmode = LZMA_FINISH;
415       }
416     }
417
418     /* Run the decoder, to decompress as much as possible of the data
419      * currently in the raw input buffer, filling available space in
420      * "buf"; as noted above, "opmode" will be LZMA_RUN, until we have
421      * exhausted the input stream, when it becomes LZMA_FINISH.
422      */
423     status = lzma_code( &stream, opmode );
424
425     /* We need to go round again, in case we exhausted the raw input
426      * data before we ran out of available space in "buf", except...
427      */
428     if( (status == LZMA_OK) && (opmode == LZMA_FINISH) )
429       /*
430        * ...when we've already achieved the LZMA_FINISH state,
431        * this becomes unnecessary, so we break the cycle.
432        */
433       break;
434   }
435
436   /* When we get to here, we either filled "buf" completely, or we
437    * completely exhausted the raw input stream; in either case, we
438    * return the actual number of bytes stored in "buf", (i.e. its
439    * total size, less any residual free space).
440    */
441   return max - stream.avail_out;
442 }
443
444 /*****
445  *
446  * Auxiliary function: pkgOpenArchiveStream()
447  *
448  * NOTE: Keep this AFTER the class specialisations, so that their derived
449  * class declarations are visible for object instantiation here!
450  *
451  */
452 #include <string.h>
453 #include <strings.h>
454
455 extern "C" pkgArchiveStream* pkgOpenArchiveStream( const char* filename )
456 {
457   /* Naive decompression filter selection, based on file name extension.
458    *
459    * FIXME: adopt more proactive selection method, (similar to that used
460    * by libarchive, perhaps), based on magic patterns within the file.
461    *
462    * NOTE: MS-Windows may use UNICODE file names, but distributed package
463    * archives almost certainly do not.  For our purposes, use of the POSIX
464    * Portable Character Set should suffice; we offer no concessions for
465    * any usage beyond this.
466    */
467   char *ext = strrchr( filename, '.' );
468   if( ext != NULL )
469   {
470     if( strcasecmp( ext, ".gz" ) == 0 )
471       /*
472        * We expect this input stream to be "gzip" compressed,
473        * so we return the appropriate decompressor.
474        */
475       return new pkgGzipArchiveStream( filename );
476
477     else if( strcasecmp( ext, ".bz2" ) == 0 )
478       /*
479        * We expect this input stream to be "bzip2" compressed,
480        * so again, we return the appropriate decompressor.
481        */
482       return new pkgBzipArchiveStream( filename );
483
484     else if( strcasecmp( ext, ".lzma" ) == 0 )
485       /*
486        * We expect this input stream to be "lzma" compressed,
487        * so again, we return the appropriate decompressor.
488        */
489       return new pkgLzmaArchiveStream( filename );
490
491     else if( strcasecmp( ext, ".xz" ) == 0 )
492       /*
493        * We expect this input stream to be "xz" compressed,
494        * so again, we return the appropriate decompressor.
495        */
496       return new pkgXzArchiveStream( filename );
497   }
498
499   /* If we get to here, then we didn't recognise any of the standard
500    * compression indicating file name extensions; fall through, to
501    * process the stream as raw (uncompressed) data.
502    */
503   return new pkgRawArchiveStream( filename );
504 }
505
506 /* $RCSfile$: end of file */