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