summaryrefslogtreecommitdiffstats
path: root/compression/lincompstream.hh
blob: 2e6793e05d691f58c267b178562258592a264fa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see <http://www.rasdaman.org>
* or contact Peter Baumann via <baumann@rasdaman.com>.
/
/**
 * INCLUDE: lincompstream.hh
 *
 * MODULE:  compression
 * CLASS:   r_Lin_Comp_Stream, r_Lin_Decomp_Stream
 *
 * PURPOSE:
 * Abstract base class for linear compression streams
 *
 * COMMENTS:
 *
*/

#ifndef _LINCOMPSTREAM_H_
#define _LINCOMPSTREAM_H_


#include <stdio.h>
#include <iostream>

#include "raslib/error.hh"
#include "raslib/storageman.hh"
#include "raslib/odmgtypes.hh"




class r_Parse_Params;
class RMTimer;


//@ManMemo: Module {\bf compression}

/*@Doc:
  r_Linear_Stream:
  Abstract base class for linear compression and decompression strings.
  Implements enumerator and common interface calls.
  Linear streams are used to compress or uncompress data in a given format.
  The can operate in static mode (the compressed data is stored to / read
  from memory directly) or in streaming mode (the compressed data is stored
  to / read from another linear stream, without having to buffer intermediate
  data explicitly or in its entirety). Streaming mode results in nesting
  linear streams, which can be done to arbitrary depth.
*/

class r_Linear_Stream
{
  public:
  // stream identifiers
  enum r_Lin_Stream_Format {
    r_Lin_Stream_None,
    r_Lin_Stream_RLE,
    r_Lin_Stream_ZLib,
    r_Lin_Stream_Arith,
    r_Lin_Stream_File,
    r_Lin_Stream_NUMBER	// used as error code
  };
  /// default constructor
  r_Linear_Stream( void );
  /// destructor
  virtual ~r_Linear_Stream( void );
  /// identification
  virtual r_Lin_Stream_Format get_format( void ) const = 0;
  /// get the name of the stream, returns r_Lin_Stream_Void if unknown
  virtual const char* get_name(void) const = 0;
  /// set compression parameters from a string
  virtual void set_params( const char *str ) = 0;
  /// set number of symbols in the stream (used by e.g. arithmetic coders)
  virtual int set_num_symbols( unsigned int syms );
  /// get stream identifier from name
  static r_Lin_Stream_Format get_id( const char *name );
  /**
     the name (case independent) may be one of the following

     \begin{tabular}{ll}
     none && r_No_(De)Comp_Stream\\
     rle && r_RLE_(De)Comp_Stream\\
     zlib && r_ZLib_(De)Comp_Stream\\
     arith && r_Arith_(De)Comp_Stream\\
     file && r_File_(De)Comp_Stream\\
     end{tabular}
  */
  /// return the string representation of the given format
  static const char *get_format_string( r_Lin_Stream_Format fmt );
  /// return a linear stream bank (concatenated streams), terminated by r_Lin_Stream_NUMBER
  static r_Lin_Stream_Format *get_bank_ids( const char *names );
  /// return a string representation of the stream bank (caller frees with delete[])
  static char *get_bank_string( const r_Lin_Stream_Format *ids );


  protected:
  /// instantiate the timer for benchmarking with a certain level
  void instantiate_timer( const char *func, int level=0 );
  /// parameters
  r_Parse_Params *params;
  /// timer for benchmarking; always defined to keep object size constant
  RMTimer *myTimer;
  /// the character used to separate stream names in stream banks
  static const char bankNameSep;
};


//@ManMemo: Module {\bf compression}

/// string output
extern std::ostream &operator<<( std::ostream &s, r_Linear_Stream::r_Lin_Stream_Format fmt );



//@ManMemo: Module {\bf compression}

/*@Doc:
  r_Lin_Comp_Store:
  Class abstracting between storing compressed data statically in an object of
  type r_Memory_Block_Vector or another r_Lin_Comp_Stream to unify normal and
  (nested) streaming interface. There is a high-level and a low-level interface.
  The high-level interface allows writing a specified number of bytes to the
  object (which will redirect it to memory or stream automatically) and is the
  preferred way. The low-level interface allows block-oriented, external
  compression libraries like ZLib to operate by giving it a block to store
  data to. In this case, use frag_ptr() to get the address of a block of
  memory (``fragment'') which can be written to, the maximum size of which can
  be obtained with frag_size() and write to it. After your data has been
  written, you MUST call frag_stored() with the number of bytes you wrote to
  frag_ptr(), otherwise subsequent calls of frag_ptr() will all return the
  same data. See zlibstream for an implementation using the low-level
  interface and the other streams on how the high-level interface is used.
*/

class r_Lin_Comp_Stream;
class r_Memory_Block_Vector;

class r_Lin_Comp_Store
{
  public:
  /// constructor for static mode, receiving block size for r_Memory_Block_Vector.
  r_Lin_Comp_Store( r_ULong bsize );
  /// constructor for streaming mode, receiving stream compression object and cache size
  r_Lin_Comp_Store( r_Lin_Comp_Stream *str, r_ULong csize=4096 );
  /// destructor
  ~r_Lin_Comp_Store( void );

  /// start output
  int start( r_Bytes typeSize );
  /// write data; return 0 for OK, -1 for error
  int put( const void *data, r_ULong size );
  /// write single byte
  int put( unsigned char val );
  /// stop outputting data and return size
  r_ULong stop( void );
  /// copy the data
  void copy_data( void *dest );
  /// flush data
  int flush( void );
  /// get pointer to current fragment (low-level interface)
  void *frag_ptr( void );
  /// get the remaining space in the current fragmend (low-level interface)
  r_ULong frag_size( void ) const;
  /// notify that size bytes have been store to current fragmemt (low-level interface)
  int frag_stored( r_ULong size );
  /// print status
  void print_status( std::ostream &str ) const;


  protected:
  /// memory block vector for static mode
  r_Memory_Block_Vector *mblocks;
  /// compression stream for streaming mode
  r_Lin_Comp_Stream *streamer;
  /// cache in streaming mode
  void *cache;
  /// size and current offset in both modes
  r_ULong cacheSize;
  r_ULong cacheOff;
};

extern std::ostream &operator<<( std::ostream &str, const r_Lin_Comp_Store &store );



//@ManMemo: Module {\bf compression}

/*@Doc:
  Abstract base class for linear compression streams. Memory allocation is all
  done transparently in the background. This class provides a common interface
  to compression methods like zlib or RLE. It can operate in static or streaming
  mode. In static mode, compressed data is stored explicitly in memory as a whole,
  whereas in streaming mode, data merely streams through the object and is piped
  into another object of type r_Lin_Comp_Stream; only a small amount of compressed
  data is buffered internally for more efficiency. Use set_stream(str) with str != NULL
  to activate streaming mode, using str as the receiving class.
*/

class r_Lin_Comp_Stream : public r_Linear_Stream
{
  public:
  /// default constructor
  r_Lin_Comp_Stream( void );
  /// copy constructor
  r_Lin_Comp_Stream( const r_Lin_Comp_Stream &src );
  /// destructor
  virtual ~r_Lin_Comp_Stream( void );

  /// change memory handlers (don't change between begin() ... end()!)
  virtual void set_storage_handler( const r_Storage_Man &newStore );

  /// creation
  static r_Lin_Comp_Stream* create( r_Lin_Stream_Format fmt, const char *pstr=NULL ) throw(r_Error);
  /**
     fmt may be one of the following:

     \begin{tabular}{ll}
     r_Lin_Stream_None && r_No_(De)Comp_Stream\\
     r_Lin_Stream_RLE && r_RLE_(De)Comp_Stream\\
     r_Lin_Stream_ZLib && r_ZLib_(De)Comp_Stream\\
     r_Lin_Stream_Arith && r_Arith_(De)Comp_Stream\\
     r_Lin_Stream_File && r_File_(De)Comp_Stream\\
     \end{tabular}

     In addition, theres r_Lin_Stream_NUMBER used as error code.
  */

  /// create a stream bank (format as returned by r_Linear_Stream::get_bank_ids() )
  static r_Lin_Comp_Stream* create( r_Lin_Stream_Format *ids, const char *pstr=NULL ) throw(r_Error);

  /// cloning
  virtual r_Lin_Comp_Stream* clone( void ) const = 0;
  
  /// set block size
  void set_block_size( r_ULong bsize );
  /// select streaming interface
  void set_stream( r_Lin_Comp_Stream *str );
  /*
    Streamed compression doesn't buffer the data but writes it to the specified
    lincompstream instead. This allows easy and efficient concatenation of
    compression streams.
  */
  /// get read/write streamer object
  r_Lin_Comp_Stream *get_stream( void );
  /// get read-only streamer object
  const r_Lin_Comp_Stream *get_stream( void ) const;
  /// print the name of the entire stream bank (recursively)
  void print_bank_name( std::ostream &str ) const;
  /// free all child streams (recursively set by set_stream() )
  void free_streams( void );
  /// get the name of the output file, or NULL if stream bank doesn't contain file stream
  const char *get_stream_file( void ) const;
  /// set the name of the output file if stream bank contains file stream, otherwise return 0
  int set_stream_file( const char *name );


  //@Man: Interface
  //@{
  /**
     typeSize is the size of the base type to encode which is important
     for some derived classes (e.g. RLE). Make sure that all size arguments
     must be multiples of typeSize later on. The value 1 should always
     work, but will usually not be optimal.
     the inputSize parameter of begin() is the size of the input data or
     0 for using defaults). This parameter directly influences the size
     of the input buffer for some streams and should therefore be used
     with care.
  */
  /// begin compression
  virtual int begin( r_Bytes typeSize, r_ULong inputSize=0 ) = 0;
  /// write data to stream
  virtual int put( const void* data, r_ULong size ) = 0;
  /// end compression
  virtual void* end( r_ULong &size ) = 0;
  /**
     standard end call, allocates new (linear) memory, copies the data
     there and frees all internal data
  */
  /// alternative end call, just finalizes the stream and returns the size
  virtual r_ULong end( void ) = 0;
  /// copy output data into linear memory
  virtual void copy_data( void* dest ) = 0;
  //@}
  virtual void set_params( const char *str );


  protected:
  /// init the target object according to the mode
  void init_target( void );
  /// completely finished the target object
  void exit_target( void );
  /// memory management object, defaults to C-style
  r_Storage_Man mystore;
  /// storage abstraction object
  r_Lin_Comp_Store *target;
  /// compression stream for streaming mode
  r_Lin_Comp_Stream *streamer;
  /// block size for static mode
  r_ULong blockSize;
  /// automatically delete all child streams in destructor if bank constructor was used
  int autoDeleteStreams;
};


//@ManMemo: Moduke {\bf compression}

//@Doc: print the stream (bank) name of the compression stream to a C++ stream

extern std::ostream &operator<<( std::ostream &str, const r_Lin_Comp_Stream &comp );



//@ManMemo: Module {\bf compression}

/*@Doc:
  r_Lin_Decomp_Store:
  Class abstracting between loading data from raw memory or from another r_Lin_Decomp_Stream
  to unify normal and (nested) streaming interface. As in r_Lin_Comp_Store, there's a
  high-level and a low-level interface. The high-level interface can be used to request
  a specified number of bytes from the storage source (memory or another stream). The
  low-level interface can be used for external, block-oriented compression libraries
  like ZLib. Use frag_ptr() to get the start address of the input data and frag_size()
  for the maximum number of bytes you can read from there. After you read a block, you
  must call frag_read() with the size of the block as argument, otherwise frag_ptr()
  will always return the same data. In addition, you should always call ensure_data()
  before you call frag_ptr(). For an implementation of the low-level interface see
  zlibstream and the other streams on how the high-level interface should be used.
 */

class r_Lin_Decomp_Stream;

class r_Lin_Decomp_Store
{
  public:
  /// constructor for static mode
  r_Lin_Decomp_Store( void );
  /// constructor for streaming mode, receiving stream decompression object and cache size
  r_Lin_Decomp_Store( r_Lin_Decomp_Stream *str, r_ULong csize=4096 );
  /// destructor
  ~r_Lin_Decomp_Store( void );

  /// start reading data
  int start( r_Bytes typeSize, const void *data, r_ULong size );
  /// read data, returns 0 for OK, negative number of unread bytes otherwise
  int get( void *data, r_ULong size );
  /// read single byte; returns 0 for OK, -1 for error
  int get( unsigned char &val );
  /// stop reading data
  int stop( void );
  /// makes sure there's some data in the cache in streaming mode, returns -1 if EOF
  int ensure_data( void );
  /// get pointer to current fragment (low-level interface)
  const void *frag_ptr( void ) const;
  /// get the valid bytes in the current fragment (low-level interface)
  r_ULong frag_size( void ) const;
  /// notify that size bytes have been read from the current fragment
  int frag_read( r_ULong size );
  /// print status
  void print_status( std::ostream &str ) const;
  

  protected:
  /// start of compressed data in static mode
  const void *dataBase;
  /// size of compressed data in static mode
  r_ULong dataSize;
  /// current offset in compressed data in static mode
  r_ULong dataOffset;
  /// decompression stream in streaming mode
  r_Lin_Decomp_Stream *streamer;
  /// cache in streaming mode
  void *cache;
  /// cache size, current fill level and current offset in streaming mode
  r_ULong cacheSize;
  r_ULong cacheLevel;
  r_ULong cacheOff;
};

extern std::ostream &operator<<( std::ostream &str, const r_Lin_Decomp_Store &store );



//@ManMemo: Module {\bf compression}

/*@Doc:
  r_Lin_Decomp_Stream:
  Abstract base class for linear decompression streams. Linear decompression streams
  can operate in static mode (compressed data is read directly from memory) and
  streaming mode (compressed data is read from another linear decompression stream).
  In streaming mode, only a small amount of compressed data is ever buffered
  internally for more efficiency. Use set_stream(str) with str != NULL to activate
  streaming mode, using str as the stream providing the input data for this stream.
  The data and size passed to the begin() method actually belong to str and are
  passed to it automatically.
 */

class r_Lin_Decomp_Stream : public r_Linear_Stream
{
  public:
  /// default constructor
  r_Lin_Decomp_Stream( void );
  /// destructor
  virtual ~r_Lin_Decomp_Stream( void );

  /// creation
  static r_Lin_Decomp_Stream* create( r_Lin_Stream_Format fmt, const char *pstr=NULL ) throw(r_Error);
  /**
     for the values of fmt see r_Lin_Comp_Stream::create()
  */
  /// create a stream bank
  static r_Lin_Decomp_Stream* create( r_Lin_Stream_Format *ids, const char *pstr=NULL ) throw(r_Error);

  /// cloning
  virtual r_Lin_Decomp_Stream* clone( void ) const = 0;

  /// select streaming interface
  void set_stream( r_Lin_Decomp_Stream *str );
  /*
    Streamed decompression doesn't read the data from linear memory but from another
    object of type r_Lin_Decomp_Stream instead to allow easy and efficient concatenation
    of decompression streams.
  */
  /// get read/write streamer object
  r_Lin_Decomp_Stream *get_stream( void );
  /// get read-only streamer object
  const r_Lin_Decomp_Stream *get_stream( void ) const;
  /// print the name of the entire stream bank (recursively)
  void print_bank_name( std::ostream &str ) const;
  /// free all child streams
  void free_streams( void );
  /// get the name of the output file, or NULL if stream bank doesn't contain file stream
  const char *get_stream_file( void ) const;
  /// set the name of the output file if stream bank contains file stream, otherwise return 0
  int set_stream_file( const char *name );

  //@Man: Interface
  //@{
  /**
     You can use three approaches:
     \begin{enumerate}
     \item
     supply dest to begin() and use the get(size) call which will
     store data to dest and increment dest afterwards, or
     \item
     use get(buffer, size) (in that case dest is irrelevant), or
     \item
     supply dest to begin() to store the pointer internally, retrieve
     the pointer later using getDestPtr() and use it in some other
     way in get(buffer, size) calls.
     \end{enumerate}
  */
  /// get the pointer to destination stored within the object
  inline void* get_dest_ptr(void) {return destPtr;}
  /// start decompression.
  virtual int begin( r_Bytes typeSize, const void* data, r_ULong size,
		     void* dest=NULL ) = 0;
  /// get() returns 0 for OK, otherwise the negative number of non-read bytes
  virtual int get( void* buffer, r_ULong size ) = 0;
  /// get data and store it in the internal destptr (which is incremented)
  virtual int get( r_ULong size ) = 0;
  /// end decompression
  virtual int end( void ) = 0;
  //@}
  /// set compression parameters from string
  virtual void set_params( const char *str );


  protected:
  /// prepare the storage abstraction object
  void init_source( void );
  /// finished with the storage abstraction object
  void exit_source( void );
  /// default destination
  void* destPtr;
  /// storage abstraction object
  r_Lin_Decomp_Store *source;
  /// stream object in streaming mode
  r_Lin_Decomp_Stream *streamer;
  /// automatically delete all child streams in destructor if bank constructor was used
  int autoDeleteStreams;
};


//@ManMemo: Module {\bf compression}

//@Doc: print the stream (bank) name of the decompression stream to a C++ stream

extern std::ostream &operator<<( std::ostream &str, const r_Lin_Decomp_Stream &decomp );




//@ManMemo: Module {\bf compression}

/*@Doc:
  Container class for matching compression and decompression streams
*/

class r_Lin_Codec_Stream
{
  public:
  /// default constructor, should not be used
  r_Lin_Codec_Stream( void );
  /// constructor that creates the codecs
  r_Lin_Codec_Stream( r_Linear_Stream::r_Lin_Stream_Format fmt, const char *pstr=NULL );
  /**
     for the values of fmt see r_Lin_Comp_Stream::create()
  */
  /// constructor for a codec bank
  r_Lin_Codec_Stream( r_Linear_Stream::r_Lin_Stream_Format *ids, const char *pstr=NULL );

  /// copy constructor
  r_Lin_Codec_Stream( const r_Lin_Codec_Stream &lc );
  /// destructor
  ~r_Lin_Codec_Stream( void );

  /// get the stream format
  inline r_Linear_Stream::r_Lin_Stream_Format get_format( void ) {
    return comp->get_format();
  }
  /// get the compression stream
  inline r_Lin_Comp_Stream *get_comp_stream( void ) {
    return comp;
  }
  /// get the decompression stream
  inline r_Lin_Decomp_Stream *get_decomp_stream( void ) {
    return decomp;
  }


  protected:
  r_Lin_Comp_Stream *comp;
  r_Lin_Decomp_Stream *decomp;
};

#endif