ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/openbabel/zipstreamimpl.hpp
Revision: 2440
Committed: Wed Nov 16 19:42:11 2005 UTC (18 years, 8 months ago) by tim
File size: 23026 byte(s)
Log Message:
adding openbabel

File Contents

# Content
1 /*
2 zipstream Library License:
3 --------------------------
4
5 The zlib/libpng License Copyright (c) 2003 Jonathan de Halleux.
6
7 This software is provided 'as-is', without any express or implied warranty. In
8 no event will the authors be held liable for any damages arising from the use
9 of this software.
10
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it freely,
13 subject to the following restrictions:
14
15 1. The origin of this software must not be misrepresented; you must not claim
16 that you wrote the original software. If you use this software in a
17 product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
22
23 3. This notice may not be removed or altered from any source distribution
24
25 Author: Jonathan de Halleux, dehalleux@pelikhan.com, 2003
26
27 Altered by: Andreas Zieringer 2003 for OpenSG project
28 made it platform independent, gzip conform, fixed gzip footer
29
30 Altered by: Geoffrey Hutchison 2005 for Open Babel project
31 minor namespace modifications, VC++ compatibility
32 */
33
34 //*****************************************************************************
35 // template class basic_zip_streambuf
36 //*****************************************************************************
37
38 //-----------------------------------------------------------------------------
39 // PUBLIC
40 //-----------------------------------------------------------------------------
41
42 /** Construct a zip stream
43 * More info on the following parameters can be found in the zlib documentation.
44 */
45
46 template <class charT, class traits>
47 basic_zip_streambuf<charT, traits>::basic_zip_streambuf(ostream_reference ostream,
48 int level,
49 EStrategy strategy,
50 int window_size,
51 int memory_level,
52 size_t buffer_size)
53 : _ostream(ostream),
54 _output_buffer(buffer_size, 0),
55 _buffer(buffer_size, 0),
56 _crc(0)
57 {
58 _zip_stream.zalloc = (alloc_func) 0;
59 _zip_stream.zfree = (free_func) 0;
60
61 _zip_stream.next_in = NULL;
62 _zip_stream.avail_in = 0;
63 _zip_stream.avail_out = 0;
64 _zip_stream.next_out = NULL;
65
66 if(level > 9)
67 level = 9;
68
69 if(memory_level > 9)
70 memory_level = 9;
71
72 _err=deflateInit2(&_zip_stream, level, Z_DEFLATED,
73 window_size, memory_level,
74 static_cast<int>(strategy));
75
76 setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]));
77 }
78
79 /** Destructor
80 */
81 template <class charT, class traits>
82 basic_zip_streambuf<charT, traits>::~basic_zip_streambuf(void)
83 {
84 flush();
85 // _ostream.flush(); CM already done in flush()
86 _err=deflateEnd(&_zip_stream);
87 }
88
89 /** Do the synchronization
90 * @todo
91 * document correctly!
92 */
93 template <class charT, class traits>
94 int basic_zip_streambuf<charT, traits>::sync(void)
95 {
96 if(this->pptr() && this->pptr() > this->pbase())
97 {
98 /*int c =*/ overflow(EOF);
99
100 // ACHTUNG wenn das drin ist hoert er nach dem ersten endl auf!
101 /*
102 if ( c == EOF)
103 return -1;
104 */
105 }
106
107 return 0;
108 }
109
110 /** <unknown purpose>
111 * @todo
112 * document correctly!
113 */
114 template <class charT, class traits>
115 typename basic_zip_streambuf<charT, traits>::int_type
116 basic_zip_streambuf<charT, traits>::overflow(int_type c)
117 {
118 int w = static_cast<int>(this->pptr() - this->pbase());
119 if (c != EOF)
120 {
121 *this->pptr() = c;
122 ++w;
123 }
124 if (zip_to_stream(this->pbase(), w))
125 {
126 setp(this->pbase(), this->epptr() - 1);
127 return c;
128 }
129 else
130 {
131 return EOF;
132 }
133 }
134
135 /** flushes the zip buffer and output buffer.
136 *
137 * This method should be called at the end of the compression. Calling flush
138 * multiple times, will lower the compression ratio.
139 */
140 template <class charT, class traits>
141 std::streamsize basic_zip_streambuf<charT, traits>::flush(void)
142 {
143 std::streamsize written_byte_size = 0, total_written_byte_size = 0;
144
145 size_t remainder = 0;
146
147 // updating crc
148 _crc = crc32(_crc, _zip_stream.next_in,
149 _zip_stream.avail_in);
150
151 do
152 {
153 _err = deflate(&_zip_stream, Z_FINISH);
154 if(_err == Z_OK || _err == Z_STREAM_END)
155 {
156 written_byte_size = static_cast<std::streamsize>(_output_buffer.size()) - _zip_stream.avail_out;
157 total_written_byte_size += written_byte_size;
158 // ouput buffer is full, dumping to ostream
159 _ostream.write( (const char_type*) &(_output_buffer[0]),
160 static_cast<std::streamsize>(written_byte_size/sizeof(char_type)*sizeof(char)));
161
162 // checking if some bytes were not written.
163 if((remainder = written_byte_size%sizeof(char_type)) != 0)
164 {
165 // copy to the beginning of the stream
166 memcpy(&(_output_buffer[0]),
167 &(_output_buffer[written_byte_size-remainder]), remainder);
168
169 }
170
171 _zip_stream.avail_out = static_cast<uInt>(_output_buffer.size() - remainder);
172 _zip_stream.next_out = &_output_buffer[remainder];
173 }
174 }
175 while(_err == Z_OK);
176
177 _ostream.flush();
178
179 return total_written_byte_size;
180 }
181
182 /** returns a reference to the output stream
183 */
184 template <class charT, class traits> inline
185 typename basic_zip_streambuf<charT, traits>::ostream_reference
186 basic_zip_streambuf<charT, traits>::get_ostream(void) const
187 {
188 return _ostream;
189 }
190
191 /** returns the latest zlib error status
192 */
193 template <class charT, class traits> inline
194 int basic_zip_streambuf<charT, traits>::get_zerr(void) const
195 {
196 return _err;
197 }
198
199 /** returns the crc of the input data compressed so far.
200 */
201 template <class charT, class traits> inline
202 unsigned long
203 basic_zip_streambuf<charT, traits>:: get_crc(void) const
204 {
205 return _crc;
206 }
207
208 /** returns the size (bytes) of the input data compressed so far.
209 */
210 template <class charT, class traits> inline
211 unsigned long
212 basic_zip_streambuf<charT, traits>::get_in_size(void) const
213 {
214 return _zip_stream.total_in;
215 }
216
217 /** returns the size (bytes) of the compressed data so far.
218 */
219 template <class charT, class traits> inline
220 long
221 basic_zip_streambuf<charT, traits>::get_out_size(void) const
222 {
223 return _zip_stream.total_out;
224 }
225
226 //-----------------------------------------------------------------------------
227 // PRIVATE
228 //-----------------------------------------------------------------------------
229
230 /** <undocumented>
231 * @todo
232 * document!
233 */
234 template <class charT, class traits>
235 bool basic_zip_streambuf<charT, traits>::zip_to_stream(
236 char_type *buffer,
237 std::streamsize buffer_size)
238 {
239 std::streamsize written_byte_size = 0, total_written_byte_size = 0;
240
241 _zip_stream.next_in = (byte_buffer_type) buffer;
242 _zip_stream.avail_in = static_cast<uInt>(buffer_size * sizeof(char_type));
243 _zip_stream.avail_out = static_cast<uInt>(_output_buffer.size());
244 _zip_stream.next_out = &_output_buffer[0];
245 size_t remainder = 0;
246
247 // updating crc
248 _crc = crc32(_crc, _zip_stream.next_in,
249 _zip_stream.avail_in);
250
251 do
252 {
253 _err = deflate(&_zip_stream, 0);
254
255 if (_err == Z_OK || _err == Z_STREAM_END)
256 {
257 written_byte_size= static_cast<std::streamsize>(_output_buffer.size()) -
258 _zip_stream.avail_out;
259 total_written_byte_size += written_byte_size;
260 // ouput buffer is full, dumping to ostream
261
262 _ostream.write((const char_type*) &_output_buffer[0],
263 static_cast<std::streamsize>(written_byte_size / sizeof(char_type)));
264
265 // checking if some bytes were not written.
266 if((remainder = written_byte_size % sizeof(char_type)) != 0)
267 {
268 // copy to the beginning of the stream
269 memcpy(&_output_buffer[0],
270 &_output_buffer[written_byte_size-remainder],
271 remainder);
272 }
273
274 _zip_stream.avail_out = static_cast<uInt>(_output_buffer.size()-remainder);
275 _zip_stream.next_out = &_output_buffer[remainder];
276 }
277 }
278 while(_zip_stream.avail_in != 0 && _err == Z_OK);
279
280 return _err == Z_OK;
281 }
282
283
284
285
286
287
288
289 //*****************************************************************************
290 // template class basic_unzip_streambuf
291 //*****************************************************************************
292
293 //-----------------------------------------------------------------------------
294 // PUBLIC
295 //-----------------------------------------------------------------------------
296
297 /** Constructor
298 */
299 template <class charT, class traits>
300 basic_unzip_streambuf<charT, traits>::basic_unzip_streambuf(istream_reference istream,
301 int window_size,
302 size_t read_buffer_size,
303 size_t input_buffer_size)
304 : _istream(istream),
305 _input_buffer(input_buffer_size),
306 _buffer(read_buffer_size),
307 _crc(0)
308 {
309 // setting zalloc, zfree and opaque
310 _zip_stream.zalloc = (alloc_func) 0;
311 _zip_stream.zfree = (free_func) 0;
312
313 _zip_stream.next_in = NULL;
314 _zip_stream.avail_in = 0;
315 _zip_stream.avail_out = 0;
316 _zip_stream.next_out = NULL;
317
318 _err = inflateInit2(&_zip_stream, window_size);
319
320 this->setg(&_buffer[0] + 4, // beginning of putback area
321 &_buffer[0] + 4, // read position
322 &_buffer[0] + 4); // end position
323 }
324
325 /**
326 * @todo document!
327 */
328 template <class charT, class traits>
329 basic_unzip_streambuf<charT, traits>::~basic_unzip_streambuf(void)
330 {
331 inflateEnd(&_zip_stream);
332 }
333
334
335 /**
336 * @todo document!
337 */
338 template <class charT, class traits>
339 typename basic_unzip_streambuf<charT, traits>::int_type
340 basic_unzip_streambuf<charT, traits>::underflow(void)
341 {
342 if(this->gptr() && ( this->gptr() < this->egptr()))
343 return * reinterpret_cast<unsigned char *>(this->gptr());
344
345 int n_putback = static_cast<int>(this->gptr() - this->eback());
346 if(n_putback > 4)
347 n_putback = 4;
348
349 memcpy(&_buffer[0] + (4 - n_putback),
350 this->gptr() - n_putback,
351 n_putback * sizeof(char_type));
352
353 int num =
354 unzip_from_stream(&_buffer[0] + 4,
355 static_cast<std::streamsize>((_buffer.size() - 4) *
356 sizeof(char_type)));
357
358 if(num <= 0) // ERROR or EOF
359 return EOF;
360
361 // reset buffer pointers
362 this->setg(&_buffer[0] + (4 - n_putback), // beginning of putback area
363 &_buffer[0] + 4, // read position
364 &_buffer[0] + 4 + num); // end of buffer
365
366 // return next character
367 return * reinterpret_cast<unsigned char *>(this->gptr());
368 }
369
370 /** returns the compressed input istream
371 */
372 template <class charT, class traits> inline
373 typename basic_unzip_streambuf<charT, traits>::istream_reference
374 basic_unzip_streambuf<charT, traits>::get_istream(void)
375 {
376 return _istream;
377 }
378
379 /** returns the zlib stream structure
380 */
381 template <class charT, class traits> inline
382 z_stream &
383 basic_unzip_streambuf<charT, traits>::get_zip_stream(void)
384 {
385 return _zip_stream;
386 }
387
388 /** returns the latest zlib error state
389 */
390 template <class charT, class traits> inline
391 int
392 basic_unzip_streambuf<charT, traits>::get_zerr(void) const
393 {
394 return _err;
395 }
396
397 /** returns the crc of the uncompressed data so far
398 */
399 template <class charT, class traits> inline
400 unsigned long
401 basic_unzip_streambuf<charT, traits>::get_crc(void) const
402 {
403 return _crc;
404 }
405
406 /** returns the number of uncompressed bytes
407 */
408 template <class charT, class traits> inline
409 long
410 basic_unzip_streambuf<charT, traits>::get_out_size(void) const
411 {
412 return _zip_stream.total_out;
413 }
414
415 /** returns the number of read compressed bytes
416 */
417 template <class charT, class traits> inline
418 long
419 basic_unzip_streambuf<charT, traits>::get_in_size(void) const
420 {
421 return _zip_stream.total_in;
422 }
423
424
425 //-----------------------------------------------------------------------------
426 // PRIVATE
427 //-----------------------------------------------------------------------------
428
429 /**
430 */
431 template <class charT, class traits> inline
432 void
433 basic_unzip_streambuf<charT, traits>::put_back_from_zip_stream(void)
434 {
435 if(_zip_stream.avail_in == 0)
436 return;
437
438 _istream.clear(std::ios::goodbit);
439 _istream.seekg(-intf(_zip_stream.avail_in),
440 std::ios_base::cur);
441
442 _zip_stream.avail_in = 0;
443 }
444
445 /**
446 */
447 template <class charT, class traits> inline
448 std::streamsize
449 basic_unzip_streambuf<charT, traits>::unzip_from_stream(char_type* buffer,
450 std::streamsize buffer_size)
451 {
452 _zip_stream.next_out =
453 (byte_buffer_type) buffer;
454 _zip_stream.avail_out =
455 static_cast<uInt>(buffer_size * sizeof(char_type));
456 size_t count = _zip_stream.avail_in;
457
458 do
459 {
460 if(_zip_stream.avail_in == 0)
461 count=fill_input_buffer();
462
463 if(_zip_stream.avail_in)
464 {
465 _err = inflate(&_zip_stream, Z_SYNC_FLUSH);
466 }
467 }
468 while(_err==Z_OK && _zip_stream.avail_out != 0 && count != 0);
469
470 // updating crc
471 _crc = crc32(_crc, (byte_buffer_type) buffer,
472 buffer_size - _zip_stream.avail_out / sizeof(char_type));
473
474 std::streamsize n_read =
475 buffer_size - _zip_stream.avail_out / sizeof(char_type);
476
477 // check if it is the end
478 if (_err == Z_STREAM_END)
479 put_back_from_zip_stream();
480
481 return n_read;
482 }
483
484
485 /**
486 */
487 template <class charT, class traits> inline
488 size_t
489 basic_unzip_streambuf<charT, traits>::fill_input_buffer(void)
490 {
491 _zip_stream.next_in = &_input_buffer[0];
492 _istream.read((char_type*) &_input_buffer[0],
493 static_cast<std::streamsize>(_input_buffer.size() /
494 sizeof(char_type)));
495
496 return _zip_stream.avail_in = _istream.gcount()*sizeof(char_type);
497 }
498
499
500
501
502
503
504
505 //*****************************************************************************
506 // template class basic_zip_ostream
507 //*****************************************************************************
508
509 //-----------------------------------------------------------------------------
510 // PUBLIC
511 //-----------------------------------------------------------------------------
512
513 /**
514 */
515 template <class charT, class traits> inline
516 basic_zip_ostream<charT, traits>::basic_zip_ostream(ostream_reference ostream,
517 bool is_gzip,
518 int level,
519 EStrategy strategy,
520 int window_size,
521 int memory_level,
522 size_t buffer_size) :
523 basic_zip_streambuf<charT, traits>(ostream, level, strategy, window_size,
524 memory_level, buffer_size),
525 std::basic_ostream<charT, traits>(this),
526 _is_gzip(is_gzip),
527 _added_footer(false)
528 {
529 if(_is_gzip)
530 add_header();
531 }
532
533 /** Destructor
534 */
535 template <class charT, class traits>
536 basic_zip_ostream<charT, traits>::~basic_zip_ostream(void)
537 {
538 if(_is_gzip)
539 add_footer();
540 }
541
542 /** returns true if it is a gzip
543 */
544 template <class charT, class traits> inline
545 bool basic_zip_ostream<charT, traits>::is_gzip(void) const
546 {
547 return _is_gzip;
548 }
549
550 /** flush inner buffer and zipper buffer
551 */
552
553 template <class charT, class traits> inline
554 basic_zip_ostream<charT, traits>& basic_zip_ostream<charT, traits>::zflush(void)
555 {
556 static_cast<std::basic_ostream<charT, traits> *>(this)->flush();
557 static_cast<basic_zip_streambuf<charT, traits> *>(this)->flush();
558 return *this;
559 }
560
561 template <class charT, class traits> inline
562 void basic_zip_ostream<charT, traits>::finished(void)
563 {
564 if(_is_gzip)
565 add_footer();
566 else
567 zflush();
568 }
569
570
571 //-----------------------------------------------------------------------------
572 // PRIVATE
573 //-----------------------------------------------------------------------------
574
575 /**
576 * @todo document!
577 */
578 template <class charT, class traits>
579 basic_zip_ostream<charT,traits>& basic_zip_ostream<charT, traits>::add_header(void)
580 {
581 char_type zero = 0;
582
583 this->get_ostream() << static_cast<char_type>(detail::gz_magic[0])
584 << static_cast<char_type>(detail::gz_magic[1])
585 << static_cast<char_type>(Z_DEFLATED)
586 << zero //flags
587 << zero<<zero<<zero<<zero // time
588 << zero //xflags
589 << static_cast<char_type>(OS_CODE);
590
591 return *this;
592 }
593
594 /**
595 * @todo document!
596 */
597 template <class charT, class traits>
598 basic_zip_ostream<charT,traits>& basic_zip_ostream<charT, traits>::add_footer(void)
599 {
600 if(_added_footer)
601 return *this;
602
603 zflush();
604
605 _added_footer = true;
606
607 // Writes crc and length in LSB order to the stream.
608 unsigned long crc = this->get_crc();
609 for(int n=0;n<4;++n)
610 {
611 this->get_ostream().put((int)(crc & 0xff));
612 crc >>= 8;
613 }
614
615 unsigned long length = this->get_in_size();
616 for(int m=0;m<4;++m)
617 {
618 this->get_ostream().put((int)(length & 0xff));
619 length >>= 8;
620 }
621
622 return *this;
623 }
624
625
626
627
628
629
630 //*****************************************************************************
631 // template class basic_zip_istream
632 //*****************************************************************************
633
634 //-----------------------------------------------------------------------------
635 // PUBLIC
636 //-----------------------------------------------------------------------------
637
638 /** Constructor
639 */
640 template <class charT, class traits>
641 basic_zip_istream<charT, traits>::basic_zip_istream(istream_reference istream,
642 int window_size,
643 size_t read_buffer_size,
644 size_t input_buffer_size)
645 : basic_unzip_streambuf<charT, traits>(istream, window_size,
646 read_buffer_size, input_buffer_size),
647 std::basic_istream<charT, traits>(this),
648 _is_gzip(false),
649 _gzip_crc(0),
650 _gzip_data_size(0)
651 {
652 if(this->get_zerr() == Z_OK)
653 check_header();
654 }
655
656 /** returns true if it is a gzip file
657 */
658 template <class charT, class traits> inline
659 bool
660 basic_zip_istream<charT, traits>::is_gzip(void) const
661 {
662 return _is_gzip;
663 }
664
665 /** return crc check result
666 *
667 * This must be called after the reading of compressed data is finished! This
668 * method compares it to the crc of the uncompressed data.
669 *
670 * \return true if crc check is succesful
671 */
672 template <class charT, class traits> inline
673 bool
674 basic_zip_istream<charT, traits>::check_crc(void)
675 {
676 read_footer();
677 return this->get_crc() == _gzip_crc;
678 }
679
680 /** return data size check
681 */
682 template <class charT, class traits> inline
683 bool
684 basic_zip_istream<charT, traits>::check_data_size(void) const
685 {
686 return this->get_out_size() == _gzip_data_size;
687 }
688
689 /** return the crc value in the file
690 */
691 template <class charT, class traits> inline
692 long
693 basic_zip_istream<charT, traits>::get_gzip_crc(void) const
694 {
695 return _gzip_crc;
696 }
697
698 /** return the data size in the file
699 */
700 template <class charT, class traits> inline
701 long
702 basic_zip_istream<charT, traits>::get_gzip_data_size(void) const
703 {
704 return _gzip_data_size;
705 }
706
707 //-----------------------------------------------------------------------------
708 // PROTECTED
709 //-----------------------------------------------------------------------------
710
711 /**
712 * @todo document!
713 */
714 template <class charT, class traits>
715 int
716 basic_zip_istream<charT, traits>::check_header(void)
717 {
718 int method; /* method byte */
719 int flags; /* flags byte */
720 uInt len;
721 int c;
722 int err=0;
723 z_stream &zip_stream = this->get_zip_stream();
724
725 /* Check the gzip magic header */
726 for(len = 0; len < 2; len++)
727 {
728 c = (int)this->get_istream().get();
729 if (c != detail::gz_magic[len])
730 {
731 if (len != 0)
732 this->get_istream().unget();
733 if (c!= EOF)
734 {
735 this->get_istream().unget();
736 }
737
738 err = zip_stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
739 _is_gzip = false;
740 return err;
741 }
742 }
743
744 _is_gzip = true;
745 method = (int)this->get_istream().get();
746 flags = (int)this->get_istream().get();
747 if (method != Z_DEFLATED || (flags & detail::gz_reserved) != 0)
748 {
749 err = Z_DATA_ERROR;
750 return err;
751 }
752
753 /* Discard time, xflags and OS code: */
754 for (len = 0; len < 6; len++)
755 this->get_istream().get();
756
757 if ((flags & detail::gz_extra_field) != 0)
758 {
759 /* skip the extra field */
760 len = (uInt)this->get_istream().get();
761 len += ((uInt)this->get_istream().get())<<8;
762 /* len is garbage if EOF but the loop below will quit anyway */
763 while (len-- != 0 && this->get_istream().get() != EOF) ;
764 }
765 if ((flags & detail::gz_orig_name) != 0)
766 {
767 /* skip the original file name */
768 while ((c = this->get_istream().get()) != 0 && c != EOF) ;
769 }
770 if ((flags & detail::gz_comment) != 0)
771 {
772 /* skip the .gz file comment */
773 while ((c = this->get_istream().get()) != 0 && c != EOF) ;
774 }
775 if ((flags & detail::gz_head_crc) != 0)
776 { /* skip the header crc */
777 for (len = 0; len < 2; len++)
778 this->get_istream().get();
779 }
780 err = this->get_istream().eof() ? Z_DATA_ERROR : Z_OK;
781
782 return err;
783 }
784
785 /**
786 * @todo document!
787 */
788 template <class charT, class traits>
789 void
790 basic_zip_istream<charT, traits>::read_footer(void)
791 {
792 if(_is_gzip)
793 {
794 _gzip_crc = 0;
795 for(int n=0;n<4;++n)
796 _gzip_crc += ((((int) this->get_istream().get()) & 0xff) << (8*n));
797
798 _gzip_data_size = 0;
799 for(int n=0;n<4;++n)
800 _gzip_data_size +=
801 ((((int) this->get_istream().get()) & 0xff) << (8*n));
802 }
803 }