00001 #ifndef UTIL_COMPRESS__ZLIB__HPP 00002 #define UTIL_COMPRESS__ZLIB__HPP 00003 00004 /* $Id: zlib.hpp 169067 2009-08-25 13:41:52Z ivanov $ 00005 * =========================================================================== 00006 * 00007 * PUBLIC DOMAIN NOTICE 00008 * National Center for Biotechnology Information 00009 * 00010 * This software/database is a "United States Government Work" under the 00011 * terms of the United States Copyright Act. It was written as part of 00012 * the author's official duties as a United States Government employee and 00013 * thus cannot be copyrighted. This software/database is freely available 00014 * to the public for use. The National Library of Medicine and the U.S. 00015 * Government have not placed any restriction on its use or reproduction. 00016 * 00017 * Although all reasonable efforts have been taken to ensure the accuracy 00018 * and reliability of the software and data, the NLM and the U.S. 00019 * Government do not and cannot warrant the performance or results that 00020 * may be obtained by using this software or data. The NLM and the U.S. 00021 * Government disclaim all warranties, express or implied, including 00022 * warranties of performance, merchantability or fitness for any particular 00023 * purpose. 00024 * 00025 * Please cite the author in any work or product based on this material. 00026 * 00027 * =========================================================================== 00028 * 00029 * Author: Vladimir Ivanov 00030 * 00031 */ 00032 00033 /// @file zlib.hpp 00034 /// ZLib Compression API. 00035 /// 00036 /// CZipCompression - base methods for compression/decompression 00037 /// memory buffers and files. 00038 /// CZipCompressionFile - allow read/write operations on files in 00039 /// zlib or gzip (.gz) format. 00040 /// CZipCompressor - zlib based compressor 00041 /// (used in CZipStreamCompressor). 00042 /// CZipDecompressor - zlib based decompressor 00043 /// (used in CZipStreamDecompressor). 00044 /// CZipStreamCompressor - zlib based compression stream processor 00045 /// (see util/compress/stream.hpp for details). 00046 /// CZipStreamDecompressor - zlib based decompression stream processor 00047 /// (see util/compress/stream.hpp for details). 00048 /// 00049 /// The zlib documentation can be found here: 00050 /// http://zlib.org, or 00051 /// http://www.gzip.org/zlib/manual.html 00052 00053 00054 #include <util/compress/stream.hpp> 00055 00056 /** @addtogroup Compression 00057 * 00058 * @{ 00059 */ 00060 00061 BEGIN_NCBI_SCOPE 00062 00063 00064 ////////////////////////////////////////////////////////////////////////////// 00065 // 00066 // Special compressor's parameters (description from zlib docs) 00067 // 00068 // <window_bits> 00069 // This parameter is the base two logarithm of the window size 00070 // (the size of the history buffer). It should be in the range 8..15 for 00071 // this version of the library. Larger values of this parameter result 00072 // in better compression at the expense of memory usage. 00073 // 00074 // <mem_level> 00075 // The "mem_level" parameter specifies how much memory should be 00076 // allocated for the internal compression state. mem_level=1 uses minimum 00077 // memory but is slow and reduces compression ratio; mem_level=9 uses 00078 // maximum memory for optimal speed. The default value is 8. See zconf.h 00079 // for total memory usage as a function of windowBits and memLevel. 00080 // 00081 // <strategy> 00082 // The strategy parameter is used to tune the compression algorithm. 00083 // Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data 00084 // produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force 00085 // Huffman encoding only (no string match). Filtered data consists mostly 00086 // of small values with a somewhat random distribution. In this case, 00087 // the compression algorithm is tuned to compress them better. The effect 00088 // of Z_FILTERED is to force more Huffman coding and less string matching; 00089 // it is somewhat intermediate between Z_DEFAULT and Z_HUFFMAN_ONLY. 00090 // The strategy parameter only affects the compression ratio but not the 00091 // correctness of the compressed output even if it is not set appropriately. 00092 00093 // Use default values, defined in zlib library 00094 const int kZlibDefaultWbits = -1; 00095 const int kZlibDefaultMemLevel = -1; 00096 const int kZlibDefaultStrategy = -1; 00097 const int kZlibDefaultCompression = -1; 00098 00099 00100 ///////////////////////////////////////////////////////////////////////////// 00101 /// 00102 /// CZipCompression -- 00103 /// 00104 /// Define a base methods for compression/decompression memory buffers 00105 /// and files. 00106 00107 class CZipCompression : public CCompression 00108 { 00109 public: 00110 /// Compression/decompression flags. 00111 enum EFlags { 00112 ///< Allow transparent reading data from buffer/file/stream 00113 ///< regardless is it compressed or not. But be aware, 00114 ///< if data source contains broken data and API cannot detect that 00115 ///< it is compressed data, that you can get binary instead of 00116 ///< decompressed data. By default this flag is OFF. 00117 ///< NOTE: zlib v1.1.4 and earlier have a bug in decoding. 00118 ///< In some cases decompressor can produce output data on invalid 00119 ///< compressed data. So, this is not recommended to use this flag 00120 ///< with old zlib versions. 00121 fAllowTransparentRead = (1<<0), 00122 ///< Check (and skip) file header for decompression stream 00123 fCheckFileHeader = (1<<1), 00124 ///< Use gzip (.gz) file format to write into compression stream 00125 ///< (the archive also can store file name and file modification 00126 ///< date in this format) 00127 fWriteGZipFormat = (1<<2), 00128 ///< Allow concatenated gzip files. 00129 ///< Multiple compressed files can be concatenated into one file. 00130 ///< In this case, decompressor will try to extract all members 00131 ///< at once. But note, that better compression can be usually 00132 ///< obtained if all members are decompressed and then recompressed 00133 ///< in a single step. 00134 fAllowConcatenatedGZip = (1<<3), 00135 /// Set of flags for gzip file support. 00136 fGZip = fCheckFileHeader | fWriteGZipFormat | fAllowConcatenatedGZip, 00137 ///< This flag can be used only with DecompressFile[IntoDir](). 00138 ///< It allow to restore the original file name and/or time stamp stored 00139 ///< in the file header, if present. 00140 ///< @sa DecompressFile, DecompressFileIntoDir 00141 fRestoreFileAttr = (1<<4) 00142 }; 00143 typedef CZipCompression::TFlags TZipFlags; ///< Bitwise OR of EFlags 00144 00145 /// Constructor. 00146 CZipCompression( 00147 ELevel level = eLevel_Default, 00148 int window_bits = kZlibDefaultWbits, // [8..15] 00149 int mem_level = kZlibDefaultMemLevel, // [1..9] 00150 int strategy = kZlibDefaultStrategy // [0..2] 00151 ); 00152 00153 /// Destructor. 00154 virtual ~CZipCompression(void); 00155 00156 /// Return name and version of the compression library. 00157 virtual CVersionInfo GetVersion(void) const; 00158 00159 /// Returns default compression level for a compression algorithm. 00160 virtual ELevel GetDefaultLevel(void) const 00161 { return ELevel(kZlibDefaultCompression); }; 00162 00163 // 00164 // Utility functions 00165 // 00166 00167 /// Compress data in the buffer. 00168 /// 00169 /// Altogether, the total size of the destination buffer must be little 00170 /// more then size of the source buffer. 00171 /// @param src_buf 00172 /// Source buffer. 00173 /// @param src_len 00174 /// Size of data in source buffer. 00175 /// @param dst_buf 00176 /// Destination buffer. 00177 /// @param dst_size 00178 /// Size of destination buffer. 00179 /// @param dst_len 00180 /// Size of compressed data in destination buffer. 00181 /// @return 00182 /// Return TRUE if operation was succesfully or FALSE otherwise. 00183 /// On success, 'dst_buf' contains compressed data of dst_len size. 00184 /// @sa 00185 /// EstimateCompressionBufferSize, DecompressBuffer 00186 virtual bool CompressBuffer( 00187 const void* src_buf, size_t src_len, 00188 void* dst_buf, size_t dst_size, 00189 /* out */ size_t* dst_len 00190 ); 00191 00192 /// Decompress data in the buffer. 00193 /// 00194 /// @note 00195 /// The decompressor stops and returns TRUE, if it find logical 00196 /// end in the compressed data, even not all compressed data was processed. 00197 /// Only for case of decompressing concatenated gzip files in memory. 00198 /// it try to decompress data behind of logical end of recurrent gzip chunk, 00199 /// to check on next portion of data. See fCheckFileHeader, 00200 /// fAllowConcatenatedGZip and fGZip flags description. 00201 /// @param src_buf 00202 /// Source buffer. 00203 /// @param src_len 00204 /// Size of data in source buffer. 00205 /// @param dst_buf 00206 /// Destination buffer. 00207 /// @param dst_size 00208 /// Size of destination buffer. 00209 /// @param dst_len 00210 /// Size of decompressed data in destination buffer. 00211 /// @return 00212 /// Return TRUE if operation was succesfully or FALSE otherwise. 00213 /// On success, 'dst_buf' contains decompressed data of dst_len size. 00214 /// @sa 00215 /// CompressBuffer, EFlags 00216 virtual bool DecompressBuffer( 00217 const void* src_buf, size_t src_len, 00218 void* dst_buf, size_t dst_size, 00219 /* out */ size_t* dst_len 00220 ); 00221 00222 /// Estimate buffer size for data compression. 00223 /// 00224 /// The function shall estimate the size of buffer required to compress 00225 /// specified number of bytes of data using the CompressBuffer() function. 00226 /// This function may return a conservative value that may be larger 00227 /// than 'src_len'. 00228 /// @param src_len 00229 /// Size of compressed data. 00230 /// @return 00231 /// Estimated buffer size. 00232 /// Return -1 on error, or if this method is not supported by current 00233 /// version of the zlib library. 00234 /// @sa 00235 /// CompressBuffer 00236 long EstimateCompressionBufferSize(size_t src_len); 00237 00238 /// Compress file. 00239 /// 00240 /// @param src_file 00241 /// File name of source file. 00242 /// @param dst_file 00243 /// File name of result file. 00244 /// @param buf_size 00245 /// Buffer size used to read/write files. 00246 /// @return 00247 /// Return TRUE on success, FALSE on error. 00248 /// @sa 00249 /// DecompressFile, DecompressFileIntoDir 00250 /// @note 00251 /// This method, as well as some gzip utilities, always 00252 /// keeps the original file name and timestamp in 00253 /// the compressed file. On this moment DecompressFile() 00254 /// do not use original file name at all, but be aware... 00255 /// If you assign different base name to destination 00256 /// compressed file, that behavior of decompression utilities 00257 /// on different platforms may differ. 00258 /// For example, WinZip on MS Windows always restore 00259 /// original file name and timestamp stored in the file. 00260 /// UNIX gunzip have -N option for this, but by default 00261 /// do not use it, and just creates a decompressed file with 00262 /// the name of the compressed file without .gz extention. 00263 virtual bool CompressFile( 00264 const string& src_file, 00265 const string& dst_file, 00266 size_t buf_size = kCompressionDefaultBufSize 00267 ); 00268 00269 /// Decompress file. 00270 /// 00271 /// @param src_file 00272 /// File name of source file. 00273 /// @param dst_file 00274 /// File name of result file. 00275 /// @param buf_size 00276 /// Buffer size used to read/write files. 00277 /// @return 00278 /// Return TRUE on success, FALSE on error. 00279 /// @sa 00280 /// CompressFile, DecompressFileIntoDir 00281 /// @note 00282 /// CompressFile() method, as well as some gzip utilities, 00283 /// always keeps the original file name and timestamp in 00284 /// the compressed file. If fRestoreFileAttr flag is set, 00285 /// that time stamp, stored in the file header will be restored. 00286 /// The original file name cannot be restored here, 00287 /// see DecompressFileIntoDir(). 00288 virtual bool DecompressFile( 00289 const string& src_file, 00290 const string& dst_file, 00291 size_t buf_size = kCompressionDefaultBufSize 00292 ); 00293 00294 /// Decompress file into specified directory. 00295 /// 00296 /// @param src_file 00297 /// File name of source file. 00298 /// @param dst_dir 00299 /// Destination directory. 00300 /// @param buf_size 00301 /// Buffer size used to read/write files. 00302 /// @return 00303 /// Return TRUE on success, FALSE on error. 00304 /// @sa 00305 /// CompressFile, DecompressFile 00306 /// @note 00307 /// CompressFile() method, as well as some gzip utilities, 00308 /// always keeps the original file name and timestamp in 00309 /// the compressed file. If fRestoreFileAttr flag is set, 00310 /// that original file name and time stamp, stored in 00311 /// the file header will be restored. If not, that destination 00312 /// file will be named as archive name without extention. 00313 virtual bool DecompressFileIntoDir( 00314 const string& src_file, 00315 const string& dst_dir, 00316 size_t buf_size = kCompressionDefaultBufSize 00317 ); 00318 00319 /// Structure to keep compressed file information. 00320 struct SFileInfo { 00321 string name; 00322 string comment; 00323 time_t mtime; 00324 SFileInfo(void) : mtime(0) {}; 00325 }; 00326 00327 protected: 00328 /// Format string with last error description. 00329 /// If pos equl to 0, that use internal m_Stream's position to report. 00330 string FormatErrorMessage(string where, unsigned long pos = 0) const; 00331 00332 protected: 00333 void* m_Stream; ///< Compressor stream. 00334 int m_WindowBits; ///< The base two logarithm of the window size 00335 ///< (the size of the history buffer). 00336 int m_MemLevel; ///< The allocation memory level for the 00337 ///< internal compression state. 00338 int m_Strategy; ///< The parameter to tune compression algorithm. 00339 }; 00340 00341 00342 ///////////////////////////////////////////////////////////////////////////// 00343 /// 00344 /// CZipCompressionFile -- 00345 /// 00346 /// Allow read/write operations on files in zlib or gzip (.gz) formats. 00347 /// Throw exceptions on critical errors. 00348 00349 class CZipCompressionFile : public CZipCompression, 00350 public CCompressionFile 00351 { 00352 public: 00353 /// Constructor. 00354 /// For a special parameters description see CZipCompression. 00355 CZipCompressionFile( 00356 const string& file_name, 00357 EMode mode, 00358 ELevel level = eLevel_Default, 00359 int window_bits = kZlibDefaultWbits, 00360 int mem_level = kZlibDefaultMemLevel, 00361 int strategy = kZlibDefaultStrategy 00362 ); 00363 /// Conventional constructor. 00364 /// For a special parameters description see CZipCompression. 00365 CZipCompressionFile( 00366 ELevel level = eLevel_Default, 00367 int window_bits = kZlibDefaultWbits, 00368 int mem_level = kZlibDefaultMemLevel, 00369 int strategy = kZlibDefaultStrategy 00370 ); 00371 00372 /// Destructor 00373 ~CZipCompressionFile(void); 00374 00375 /// Opens a compressed file for reading or writing. 00376 /// 00377 /// @param file_name 00378 /// File name of the file to open. 00379 /// @param mode 00380 /// File open mode. 00381 /// @return 00382 /// TRUE if file was opened succesfully or FALSE otherwise. 00383 /// @sa 00384 /// CZipCompression, Read, Write, Close 00385 virtual bool Open(const string& file_name, EMode mode); 00386 00387 /// Opens a compressed file for reading or writing. 00388 /// 00389 /// Do the same as standard Open(), but can also get/set file info. 00390 /// @param file_name 00391 /// File name of the file to open. 00392 /// @param mode 00393 /// File open mode. 00394 /// @param info 00395 /// Pointer to file information structure. If it is not NULL, 00396 /// that it will be used to get information about compressed file 00397 /// in the read mode, and set it in the write mode for gzip files. 00398 /// @return 00399 /// TRUE if file was opened succesfully or FALSE otherwise. 00400 /// @sa 00401 /// CZipCompression, Read, Write, Close 00402 virtual bool Open(const string& file_name, EMode mode, SFileInfo* info); 00403 00404 /// Read data from compressed file. 00405 /// 00406 /// Read up to "len" uncompressed bytes from the compressed file "file" 00407 /// into the buffer "buf". 00408 /// @param buf 00409 /// Buffer for requested data. 00410 /// @param len 00411 /// Number of bytes to read. 00412 /// @return 00413 /// Number of bytes actually read (0 for end of file, -1 for error). 00414 /// The number of really readed bytes can be less than requested. 00415 /// @sa 00416 /// Open, Write, Close 00417 virtual long Read(void* buf, size_t len); 00418 00419 /// Write data to compressed file. 00420 /// 00421 /// Writes the given number of uncompressed bytes from the buffer 00422 /// into the compressed file. 00423 /// @param buf 00424 /// Buffer with written data. 00425 /// @param len 00426 /// Number of bytes to write. 00427 /// @return 00428 /// Number of bytes actually written or -1 for error. 00429 /// @sa 00430 /// Open, Read, Close 00431 virtual long Write(const void* buf, size_t len); 00432 00433 /// Close compressed file. 00434 /// 00435 /// Flushes all pending output if necessary, closes the compressed file. 00436 /// @return 00437 /// TRUE on success, FALSE on error. 00438 /// @sa 00439 /// Open, Read, Write 00440 virtual bool Close(void); 00441 00442 protected: 00443 /// Get error code/description of last stream operation (m_Stream). 00444 /// It can be received using GetErrorCode()/GetErrorDescription() methods. 00445 void GetStreamError(void); 00446 00447 protected: 00448 EMode m_Mode; ///< I/O mode (read/write). 00449 CNcbiFstream* m_File; ///< File stream. 00450 CCompressionIOStream* m_Stream; ///< [De]comression stream. 00451 }; 00452 00453 00454 ///////////////////////////////////////////////////////////////////////////// 00455 /// 00456 /// CZipCompressor -- zlib based compressor 00457 /// 00458 /// Used in CZipStreamCompressor. 00459 /// @sa CZipStreamCompressor, CZipCompression, CCompressionProcessor 00460 00461 class CZipCompressor : public CZipCompression, 00462 public CCompressionProcessor 00463 { 00464 public: 00465 /// Constructor. 00466 CZipCompressor( 00467 ELevel level = eLevel_Default, 00468 int window_bits = kZlibDefaultWbits, 00469 int mem_level = kZlibDefaultMemLevel, 00470 int strategy = kZlibDefaultStrategy, 00471 TZipFlags flags = 0 00472 ); 00473 /// Destructor. 00474 virtual ~CZipCompressor(void); 00475 00476 /// Set information about compressed file. 00477 /// 00478 /// Used for compression of gzip files. 00479 void SetFileInfo(const SFileInfo& info); 00480 00481 protected: 00482 virtual EStatus Init (void); 00483 virtual EStatus Process(const char* in_buf, size_t in_len, 00484 char* out_buf, size_t out_size, 00485 /* out */ size_t* in_avail, 00486 /* out */ size_t* out_avail); 00487 virtual EStatus Flush (char* out_buf, size_t out_size, 00488 /* out */ size_t* out_avail); 00489 virtual EStatus Finish (char* out_buf, size_t out_size, 00490 /* out */ size_t* out_avail); 00491 virtual EStatus End (void); 00492 00493 private: 00494 unsigned long m_CRC32; ///< CRC32 for compressed data. 00495 string m_Cache; ///< Buffer to cache small pieces of data. 00496 bool m_NeedWriteHeader; 00497 ///< Is true if needed to write a file header. 00498 SFileInfo m_FileInfo; ///< Compressed file info. 00499 }; 00500 00501 00502 00503 ///////////////////////////////////////////////////////////////////////////// 00504 /// 00505 /// CZipCompressor -- zlib based decompressor 00506 /// 00507 /// Used in CZipStreamCompressor. 00508 /// @sa CZipStreamCompressor, CZipCompression, CCompressionProcessor 00509 00510 class CZipDecompressor : public CZipCompression, 00511 public CCompressionProcessor 00512 { 00513 public: 00514 /// Constructor. 00515 CZipDecompressor( 00516 int window_bits = kZlibDefaultWbits, 00517 TZipFlags flags = 0 00518 ); 00519 /// Destructor. 00520 virtual ~CZipDecompressor(void); 00521 00522 protected: 00523 virtual EStatus Init (void); 00524 virtual EStatus Process(const char* in_buf, size_t in_len, 00525 char* out_buf, size_t out_size, 00526 /* out */ size_t* in_avail, 00527 /* out */ size_t* out_avail); 00528 virtual EStatus Flush (char* out_buf, size_t out_size, 00529 /* out */ size_t* out_avail); 00530 virtual EStatus Finish (char* out_buf, size_t out_size, 00531 /* out */ size_t* out_avail); 00532 virtual EStatus End (void); 00533 00534 private: 00535 bool m_NeedCheckHeader; ///< TRUE if needed to check to file header. 00536 bool m_IsGZ; ///< TRUE if data have gzip format. 00537 size_t m_SkipInput; ///< Number of bytes to skip from input stream. 00538 ///< Used to process concatenated .gz files. 00539 string m_Cache; ///< Buffer to cache small pieces of data. 00540 }; 00541 00542 00543 00544 ///////////////////////////////////////////////////////////////////////////// 00545 /// 00546 /// CZipStreamCompressor -- zlib based compression stream processor 00547 /// 00548 /// See util/compress/stream.hpp for details of stream processing. 00549 /// @note 00550 /// Compression/decompression flags (CZipCompression:EFlags) can greatly 00551 /// affect CZipStreamCompressor behaviour. By default, compressor 00552 /// produce plain zip data, that is not compatible with gzip/gunzip utility. 00553 /// Please use appropriate flags in constructor to change default behaviour. 00554 /// @sa CCompressionStreamProcessor 00555 00556 class CZipStreamCompressor 00557 : public CCompressionStreamProcessor 00558 { 00559 public: 00560 /// Full constructor 00561 CZipStreamCompressor( 00562 CZipCompression::ELevel level, 00563 streamsize in_bufsize, 00564 streamsize out_bufsize, 00565 int window_bits, 00566 int mem_level, 00567 int strategy, 00568 CZipCompression::TZipFlags flags = 0 00569 ) 00570 : CCompressionStreamProcessor( 00571 new CZipCompressor(level,window_bits,mem_level,strategy,flags), 00572 eDelete, in_bufsize, out_bufsize) 00573 {} 00574 00575 /// Conventional constructor 00576 CZipStreamCompressor( 00577 CZipCompression::ELevel level, 00578 CZipCompression::TZipFlags flags = 0 00579 ) 00580 : CCompressionStreamProcessor( 00581 new CZipCompressor(level, kZlibDefaultWbits, 00582 kZlibDefaultMemLevel, kZlibDefaultStrategy, 00583 flags), 00584 eDelete, kCompressionDefaultBufSize, kCompressionDefaultBufSize) 00585 {} 00586 00587 /// Conventional constructor 00588 CZipStreamCompressor(CZipCompression::TZipFlags flags = 0) 00589 : CCompressionStreamProcessor( 00590 new CZipCompressor(CZipCompression::eLevel_Default, 00591 kZlibDefaultWbits, kZlibDefaultMemLevel, 00592 kZlibDefaultStrategy, flags), 00593 eDelete, kCompressionDefaultBufSize, kCompressionDefaultBufSize) 00594 {} 00595 }; 00596 00597 00598 ///////////////////////////////////////////////////////////////////////////// 00599 /// 00600 /// CZipStreamDecompressor -- zlib based decompression stream processor 00601 /// 00602 /// See util/compress/stream.hpp for details of stream processing. 00603 /// @note 00604 /// Compression/decompression flags (CZipCompression:EFlags) can greatly 00605 /// affect CZipStreamDecompressor behaviour. By default, decompressor 00606 /// do not allow data in gzip format. Please use appropriate flags 00607 /// in constructor to change default behaviour. 00608 /// @sa CCompressionStreamProcessor 00609 00610 class CZipStreamDecompressor 00611 : public CCompressionStreamProcessor 00612 { 00613 public: 00614 /// Full constructor 00615 CZipStreamDecompressor( 00616 streamsize in_bufsize, 00617 streamsize out_bufsize, 00618 int window_bits, 00619 CZipCompression::TZipFlags flags 00620 ) 00621 : CCompressionStreamProcessor( 00622 new CZipDecompressor(window_bits, flags), 00623 eDelete, in_bufsize, out_bufsize) 00624 {} 00625 00626 /// Conventional constructor 00627 CZipStreamDecompressor(CZipCompression::TZipFlags flags = 0) 00628 : CCompressionStreamProcessor( 00629 new CZipDecompressor(kZlibDefaultWbits, flags), 00630 eDelete, kCompressionDefaultBufSize, kCompressionDefaultBufSize) 00631 {} 00632 }; 00633 00634 00635 END_NCBI_SCOPE 00636 00637 00638 /* @} */ 00639 00640 #endif /* UTIL_COMPRESS__ZLIB__HPP */ 00641 00642
1.4.6
Modified on Wed Dec 09 08:17:44 2009 by modify_doxy.py rev. 173732