OSDN Git Service

Add subsystem specific sysroot mapping facility.
[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, 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   lzma_stream_initialise( &stream );
245   status = lzma_alone_decoder( &stream, memlimit() );
246 }
247
248 pkgLzmaArchiveStream::~pkgLzmaArchiveStream()
249 {
250   /* The destructor frees memory resources allocated to the decoder,
251    * and closes the input stream file descriptor.
252    *
253    * FIXME: The lzma_alone_decoder may indicate end-of-stream, before
254    * the physical input data stream is exhausted.  For now, we silently
255    * ignore any such residual data; (it is likely to be garbage anyway).
256    * Should we handle it any more explicitly?
257    */
258   lzma_end( &stream );
259   close( fd );
260 }
261
262 int pkgLzmaArchiveStream::Read( char *buf, size_t max )
263 {
264   /* Read an lzma compressed data stream; store up to "max" bytes of
265    * decompressed data into "buf".
266    * 
267    * Start by directing the decoder to use "buf", initially marking it 
268    * as "empty".
269    */
270   stream.next_out = (uint8_t *)(buf);
271   stream.avail_out = max;
272
273   while( (stream.avail_out > 0) && (status == LZMA_OK) )
274   {
275     /* "buf" hasn't been filled yet, and the decoder continues to say
276      * that more data may be available.
277      */
278     if( stream.avail_in == 0 )
279     {
280       /* We exhausted the current content of the raw input buffer;
281        * top it up again.
282        */
283       stream.next_in = streambuf;
284       if( (stream.avail_in = GetRawData( fd, streambuf, BUFSIZ )) < 0 )
285       {
286         /* FIXME: an I/O error occurred here: need to handle it!!!
287          */
288       }
289     }
290
291     /* Run the decoder, to decompress as much as possible of the data
292      * currently in the raw input buffer, filling available space in
293      * "buf"; go round again, in case we exhausted the raw input data
294      * before we ran out of available space in "buf".
295      */
296     status = lzma_code( &stream, LZMA_RUN );
297   }
298
299   /* When we get to here, we either filled "buf" completely, or we
300    * completely exhausted the raw input stream; in either case, we
301    * return the actual number of bytes stored in "buf", (i.e. its
302    * total size, less any residual free space).
303    */
304   return max - stream.avail_out;
305 }
306
307 /*****
308  *
309  * Class Implementation: pkgXzArchiveStream
310  *
311  * This class creates an input streaming interface, suitable for
312  * reading archives which have been stored with xz compression;
313  * again based on the use of liblzma.a, this implements a further
314  * adaptation of Lasse Collin's "xzdec" code, as configured for
315  * use as an xz decompressor.
316  *
317  */
318 pkgXzArchiveStream::pkgXzArchiveStream( const char *filename )
319 {
320   /* The constructor must first open a file stream...
321    */
322   if( (fd = open( filename, O_RDONLY | O_BINARY )) >= 0 )
323   {
324     /* ...then set up the lzma decoder, in appropriately
325      * initialised state...
326      */
327     lzma_stream_initialise( &stream );
328     status = lzma_stream_decoder( &stream, memlimit(), LZMA_CONCATENATED );
329
330     /* Finally, recognising that with LZMA_CONCATENATED data,
331      * we will eventually need to switch the decoder from its
332      * initial LZMA_RUN state to LZMA_FINISH, we must provide
333      * a variable to specify the active state, (which we may
334      * initialise for the LZMA_RUN state).
335      */
336     opmode = LZMA_RUN;
337   }
338 }
339
340 pkgXzArchiveStream::~pkgXzArchiveStream()
341 {
342   /* This destructor frees memory resources allocated to the decoder,
343    * and closes the input stream file descriptor; unlike the preceding
344    * case of the lzma_alone_decoder, the lzma_stream_decoder guarantees
345    * that there is no trailing garbage remaining from the input stream.
346    */
347   lzma_end( &stream );
348   close( fd );
349 }
350
351 int pkgXzArchiveStream::Read( char *buf, size_t max )
352 {
353   /* Read an xz compressed data stream; store up to "max" bytes of
354    * decompressed data into "buf".
355    * 
356    * Start by directing the decoder to use "buf", initially marking it 
357    * as "empty".
358    */
359   stream.next_out = (uint8_t *)(buf);
360   stream.avail_out = max;
361
362   while( (stream.avail_out > 0) && (status == LZMA_OK) )
363   {
364     /* "buf" hasn't been filled yet, and the decoder continues to say
365      * that more data may be available.
366      */
367     if( stream.avail_in == 0 )
368     {
369       /* We exhausted the current content of the raw input buffer;
370        * top it up again.
371        */
372       stream.next_in = streambuf;
373       if( (stream.avail_in = GetRawData( fd, streambuf, BUFSIZ )) < 0 )
374       {
375         /* FIXME: an I/O error occurred here: need to handle it!!!
376          */
377       }
378
379       else if( stream.avail_in < BUFSIZ )
380       {
381         /* A short read indicates end-of-input...
382          * Unlike the case of the lzma_alone_decoder, (as used for
383          * decompressing lzma streams), the lzma_stream_decoder, (when
384          * initialised for LZMA_CONCATENATED data, as we use here), may
385          * run lzma_code in either LZMA_RUN or LZMA_FINISH mode; the
386          * normal mode is LZMA_RUN, but we switch to LZMA_FINISH
387          * when we have exhausted the input stream.
388          */
389         opmode = LZMA_FINISH;
390       }
391     }
392
393     /* Run the decoder, to decompress as much as possible of the data
394      * currently in the raw input buffer, filling available space in
395      * "buf"; as noted above, "opmode" will be LZMA_RUN, until we have
396      * exhausted the input stream, when it becomes LZMA_FINISH.
397      */
398     status = lzma_code( &stream, opmode );
399
400     /* We need to go round again, in case we exhausted the raw input
401      * data before we ran out of available space in "buf", except...
402      */
403     if( (status == LZMA_OK) && (opmode == LZMA_FINISH) )
404       /*
405        * ...when we've already achieved the LZMA_FINISH state,
406        * this becomes unnecessary, so we break the cycle.
407        */
408       break;
409   }
410
411   /* When we get to here, we either filled "buf" completely, or we
412    * completely exhausted the raw input stream; in either case, we
413    * return the actual number of bytes stored in "buf", (i.e. its
414    * total size, less any residual free space).
415    */
416   return max - stream.avail_out;
417 }
418
419 /*****
420  *
421  * Auxiliary function: pkgOpenArchiveStream()
422  *
423  * NOTE: Keep this AFTER the class specialisations, so that their derived
424  * class declarations are visible for object instantiation here!
425  *
426  */
427 #include <string.h>
428 #include <strings.h>
429
430 extern "C" pkgArchiveStream* pkgOpenArchiveStream( const char* filename )
431 {
432   /* Naive decompression filter selection, based on file name extension.
433    *
434    * FIXME: adopt more proactive selection method, (similar to that used
435    * by libarchive, perhaps), based on magic patterns within the file.
436    *
437    * NOTE: MS-Windows may use UNICODE file names, but distributed package
438    * archives almost certainly do not.  For our purposes, use of the POSIX
439    * Portable Character Set should suffice; we offer no concessions for
440    * any usage beyond this.
441    */
442   char *ext = strrchr( filename, '.' );
443   if( ext != NULL )
444   {
445     if( strcasecmp( ext, ".gz" ) == 0 )
446       /*
447        * We expect this input stream to be "gzip" compressed,
448        * so we return the appropriate decompressor.
449        */
450       return new pkgGzipArchiveStream( filename );
451
452     else if( strcasecmp( ext, ".bz2" ) == 0 )
453       /*
454        * We expect this input stream to be "bzip2" compressed,
455        * so again, we return the appropriate decompressor.
456        */
457       return new pkgBzipArchiveStream( filename );
458
459     else if( strcasecmp( ext, ".lzma" ) == 0 )
460       /*
461        * We expect this input stream to be "lzma" compressed,
462        * so again, we return the appropriate decompressor.
463        */
464       return new pkgLzmaArchiveStream( filename );
465
466     else if( strcasecmp( ext, ".xz" ) == 0 )
467       /*
468        * We expect this input stream to be "xz" compressed,
469        * so again, we return the appropriate decompressor.
470        */
471       return new pkgXzArchiveStream( filename );
472   }
473
474   /* If we get to here, then we didn't recognise any of the standard
475    * compression indicating file name extensions; fall through, to
476    * process the stream as raw (uncompressed) data.
477    */
478   return new pkgRawArchiveStream( filename );
479 }
480
481 /* $RCSfile$: end of file */