1 /********************************************************************************
2 *                                                                               *
3 *                      B Z F i l e S t r e a m   C l a s s e s                  *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1999,2020 by Lyle Johnson. All Rights Reserved.                 *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXElement.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXObject.h"
32 #include "FXFile.h"
33 #include "FXBZFileStream.h"
34 
35 #ifdef HAVE_BZ2LIB_H
36 #include <bzlib.h>
37 
38 /*
39   Notes:
40   - Very basic compressed file I/O only.
41   - Updated for new stream classes 2003/07/08.
42   - Updated for use with FXFile 2005/09/03.
43 */
44 
45 
46 #define BLOCKSIZE100K 1         // Block size x 100,000 bytes
47 #define VERBOSITY     0         // For tracing in bzip library
48 #define WORKFACTOR    0         // See bzip2 documentation
49 #define BUFFERSIZE    8192      // Size of the buffer
50 
51 
52 /*******************************************************************************/
53 
54 
55 namespace FX {
56 
57 
58 // Used during compression
59 struct BZBlock {
60   bz_stream stream;
61   char      buffer[BUFFERSIZE];
62   };
63 
64 
65 // Create BZIP2 file stream
FXBZFileStream(const FXObject * cont)66 FXBZFileStream::FXBZFileStream(const FXObject* cont):FXFileStream(cont),bz(NULL),ac(0){
67   }
68 
69 
70 // Create and open BZIP2 file stream
FXBZFileStream(const FXString & filename,FXStreamDirection save_or_load,FXuval size)71 FXBZFileStream::FXBZFileStream(const FXString& filename,FXStreamDirection save_or_load,FXuval size):bz(NULL),ac(0){
72   open(filename,save_or_load,size);
73   }
74 
75 
76 // Save to a file
writeBuffer(FXuval)77 FXuval FXBZFileStream::writeBuffer(FXuval){
78   FXival m,n; int bzerror;
79   if(dir!=FXStreamSave){fxerror("FXBZFileStream::writeBuffer: wrong stream direction.\n");}
80   FXASSERT(begptr<=rdptr);
81   FXASSERT(rdptr<=wrptr);
82   FXASSERT(wrptr<=endptr);
83   while(rdptr<wrptr || ac==BZ_FINISH || ac==BZ_FLUSH){
84     bz->stream.next_in=(char*)rdptr;
85     bz->stream.avail_in=wrptr-rdptr;
86     bz->stream.next_out=bz->buffer;
87     bz->stream.avail_out=BUFFERSIZE;
88     bzerror=BZ2_bzCompress(&bz->stream,ac);
89     if(bzerror<BZ_OK) break;                            // Error occurred
90     m=bz->stream.next_out-bz->buffer;
91     n=file.writeBlock(bz->buffer,m);
92     if(n<m) break;                                      // Failed to write data
93     rdptr=(FXuchar*)bz->stream.next_in;
94     if(bzerror==BZ_STREAM_END) break;                   // Finished all data
95     if(bzerror==BZ_RUN_OK && ac==BZ_FLUSH) break;       // Flushed all data
96     }
97   if(rdptr<wrptr){memmove(begptr,rdptr,wrptr-rdptr);}
98   wrptr=begptr+(wrptr-rdptr);
99   rdptr=begptr;
100   return endptr-wrptr;
101   }
102 
103 
104 // Load from file
readBuffer(FXuval)105 FXuval FXBZFileStream::readBuffer(FXuval){
106   FXival n; int bzerror;
107   if(dir!=FXStreamLoad){fxerror("FXBZFileStream::readBuffer: wrong stream direction.\n");}
108   FXASSERT(begptr<=rdptr);
109   FXASSERT(rdptr<=wrptr);
110   FXASSERT(wrptr<=endptr);
111   if(rdptr<wrptr){memmove(begptr,rdptr,wrptr-rdptr);}
112   wrptr=begptr+(wrptr-rdptr);
113   rdptr=begptr;
114   while(wrptr<endptr){
115     if(bz->stream.avail_in<=0){                         // Read more input
116       n=file.readBlock(bz->buffer,BUFFERSIZE);
117       if(n<=0) break;
118       bz->stream.next_in=bz->buffer;
119       bz->stream.avail_in=n;
120       }
121     bz->stream.next_out=(char*)wrptr;
122     bz->stream.avail_out=endptr-wrptr;
123     bzerror=BZ2_bzDecompress(&bz->stream);
124     if(bzerror<BZ_OK) break;                            // Error occurred
125     wrptr=(FXuchar*)bz->stream.next_out;
126     if(bzerror==BZ_STREAM_END) break;                   // Hit end of file
127     }
128   return wrptr-rdptr;
129   }
130 
131 
132 // Try open file stream
open(const FXString & filename,FXStreamDirection save_or_load,FXuval size)133 FXbool FXBZFileStream::open(const FXString& filename,FXStreamDirection save_or_load,FXuval size){
134   if(FXFileStream::open(filename,save_or_load,size)){
135     if(callocElms(bz,1)){
136       int bzerror;
137       bz->stream.next_in=NULL;
138       bz->stream.avail_in=0;
139       bz->stream.next_out=NULL;
140       bz->stream.avail_out=0;
141       ac=BZ_RUN;
142       if(save_or_load==FXStreamLoad){
143         bzerror=BZ2_bzDecompressInit(&bz->stream,VERBOSITY,0);
144         if(bzerror==BZ_OK) return true;
145         code=FXStreamNoRead;
146         }
147       else{
148         bzerror=BZ2_bzCompressInit(&bz->stream,BLOCKSIZE100K,VERBOSITY,WORKFACTOR);
149         if(bzerror==BZ_OK) return true;
150         code=FXStreamNoWrite;
151         }
152       freeElms(bz);
153       }
154     FXFileStream::close();
155     }
156   return false;
157   }
158 
159 
160 // Flush buffer
flush()161 FXbool FXBZFileStream::flush(){
162   FXbool result;
163   int action=ac;
164   if(ac!=BZ_FINISH) ac=BZ_FLUSH;
165   result=FXStream::flush();
166   ac=action;
167   return result;
168   }
169 
170 
171 // Close file stream
close()172 FXbool FXBZFileStream::close(){
173   if(dir){
174     if(dir==FXStreamLoad){
175       FXFileStream::close();
176       BZ2_bzDecompressEnd(&bz->stream);
177       }
178     else{
179       ac=BZ_FINISH;
180       FXFileStream::close();
181       BZ2_bzCompressEnd(&bz->stream);
182       }
183     freeElms(bz);
184     return true;
185     }
186   return false;
187   }
188 
189 
190 // Destructor
~FXBZFileStream()191 FXBZFileStream::~FXBZFileStream(){
192   close();
193   }
194 
195 }
196 
197 #endif
198