00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "cmtkTypedStream.h"
00034
00035 #include <System/cmtkFileUtils.h>
00036 #include <System/cmtkConsole.h>
00037
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <cstdarg>
00041 #include <limits.h>
00042
00043 #ifdef HAVE_MALLOC_H
00044 # include <malloc.h>
00045 #endif
00046
00047 #ifdef HAVE_SYS_TIME_H
00048 # include <sys/time.h>
00049 #endif
00050
00051 #ifdef HAVE_SYS_STAT_H
00052 # include <sys/stat.h>
00053 #endif
00054
00055 namespace
00056 cmtk
00057 {
00058
00061
00062 TypedStream
00063 ::TypedStream()
00064 {
00065 this->InitInternals();
00066 }
00067
00068 TypedStream
00069 ::TypedStream
00070 ( const char *filename, const TypedStreamMode mode )
00071 {
00072 this->InitInternals();
00073 this->Open( filename, mode );
00074 }
00075
00076 TypedStream
00077 ::TypedStream
00078 ( const char *dir, const char *archive, const TypedStreamMode mode )
00079 {
00080 this->InitInternals();
00081 this->Open( dir, archive, mode );
00082 }
00083
00084 void
00085 TypedStream
00086 ::InitInternals()
00087 {
00088 File = NULL;
00089 GzFile = NULL;
00090
00091 PrecisionFloat = 6;
00092 PrecisionDouble = 10;
00093
00094 Status = TYPEDSTREAM_ERROR_NONE;
00095 DebugFlag = TYPEDSTREAM_DEBUG_OFF;
00096
00097 SplitPosition = NULL;
00098 }
00099
00100 TypedStream
00101 ::~TypedStream()
00102 {
00103 this->Close();
00104 this->InitInternals();
00105 }
00106
00107 void
00108 TypedStream
00109 ::Open
00110 ( const char *dir, const char *archive, const TypedStreamMode mode )
00111 {
00112 static char fname[PATH_MAX];
00113
00114
00115 if ( dir && *dir )
00116 {
00117 if ( static_cast<size_t>( snprintf( fname, sizeof( fname ), "%s/%s", dir, archive ) ) >= sizeof( fname ) )
00118 {
00119 StdErr << "WARNING: length of path exceeds system PATH_MAX in TypedStream::Open and will be truncated.\n";
00120 }
00121 }
00122 else
00123 {
00124 if ( static_cast<size_t>( snprintf( fname, sizeof( fname ), "%s", archive ) ) >= sizeof( fname ) )
00125 {
00126 StdErr << "WARNING: length of path exceeds system PATH_MAX in TypedStream::Open and will be truncated.\n";
00127 }
00128 }
00129
00130 if ( mode == TYPEDSTREAM_WRITE || mode == TYPEDSTREAM_WRITE_ZLIB || mode == TYPEDSTREAM_APPEND )
00131 {
00132 #ifndef _MSC_VER
00133
00134
00135 struct stat buf;
00136 if ( !stat( dir, &buf ) && S_ISDIR( buf.st_mode ) )
00137 {
00138 utimes( dir, NULL );
00139 }
00140 #endif
00141 }
00142
00143 this->Open( fname, mode );
00144 }
00145
00146 void
00147 TypedStream
00148 ::Open
00149 ( const char *filename, const TypedStreamMode mode )
00150 {
00151 Status = TYPEDSTREAM_ERROR_NONE;
00152
00153 this->Close();
00154
00155 if ( !filename)
00156 {
00157 Status = TYPEDSTREAM_ERROR_ARG;
00158 return;
00159 }
00160
00161 if ( mode != TYPEDSTREAM_READ && mode != TYPEDSTREAM_WRITE && mode != TYPEDSTREAM_WRITE_ZLIB && mode != TYPEDSTREAM_APPEND )
00162 {
00163 Status = TYPEDSTREAM_ERROR_ARG;
00164 return;
00165 }
00166
00167 if ( mode == TYPEDSTREAM_WRITE || mode == TYPEDSTREAM_WRITE_ZLIB )
00168 {
00169 if ( FileUtils::RecursiveMkPrefixDir( filename ) )
00170 {
00171 Status = TYPEDSTREAM_ERROR_SYSTEM;
00172 return;
00173 }
00174 }
00175
00176 const char *modestr = "";
00177 switch ( mode )
00178 {
00179 #ifdef _MSC_VER
00180 case TYPEDSTREAM_READ: modestr = "rb"; break;
00181 case TYPEDSTREAM_WRITE: modestr = "wb"; break;
00182 case TYPEDSTREAM_WRITE_ZLIB: modestr = "wb"; break;
00183 case TYPEDSTREAM_APPEND: modestr = "ab"; break;
00184 #else
00185 case TYPEDSTREAM_READ: modestr = "r"; break;
00186 case TYPEDSTREAM_WRITE: modestr = "w"; break;
00187 case TYPEDSTREAM_WRITE_ZLIB: modestr = "w"; break;
00188 case TYPEDSTREAM_APPEND: modestr = "a"; break;
00189 #endif
00190 }
00191
00192 if ( ! ( File = fopen( filename, modestr ) ) )
00193 {
00194 char gzName[PATH_MAX];
00195 snprintf( gzName, sizeof( gzName ), "%s.gz", filename );
00196 GzFile = gzopen( gzName, modestr );
00197 if ( ! GzFile )
00198 {
00199 Status = TYPEDSTREAM_ERROR_SYSTEM;
00200 return;
00201 }
00202 }
00203
00204 Mode = mode;
00205 switch ( Mode )
00206 {
00207 case TYPEDSTREAM_READ:
00208 if ( GzFile )
00209 {
00210 if (! gzgets( GzFile, Buffer, TYPEDSTREAM_LIMIT_BUFFER ) )
00211 {
00212 Status = TYPEDSTREAM_ERROR_FORMAT;
00213 gzclose( GzFile );
00214 return;
00215 }
00216 }
00217 else
00218 if (! fgets( Buffer, TYPEDSTREAM_LIMIT_BUFFER, File ) )
00219 {
00220 Status = TYPEDSTREAM_ERROR_FORMAT;
00221 fclose( File );
00222 File = NULL;
00223 return;
00224 }
00225
00226 if (Buffer[0] != '!' && Buffer[0] != '#')
00227 {
00228 Status = TYPEDSTREAM_ERROR_FORMAT;
00229 if ( GzFile )
00230 {
00231 gzclose( GzFile );
00232 GzFile = NULL;
00233 }
00234
00235 if ( File )
00236 {
00237 fclose( File );
00238 File = NULL;
00239 }
00240 return;
00241 }
00242 int releaseMinor, releaseMajor;
00243 if (2 != sscanf( Buffer+1, " TYPEDSTREAM %d.%d", &releaseMajor, &releaseMinor))
00244 {
00245 Status = TYPEDSTREAM_ERROR_FORMAT;
00246 if ( GzFile )
00247 {
00248 gzclose( GzFile );
00249 GzFile = NULL;
00250 }
00251
00252 if ( File )
00253 {
00254 fclose( File );
00255 File = NULL;
00256 }
00257 return;
00258 }
00259 if ( releaseMajor == 1 && releaseMinor == 0)
00260 {
00261
00262 }
00263 else
00264 if (releaseMajor == 1 && releaseMinor == 1)
00265 {
00266
00267 }
00268 else
00269 {
00270
00271 Status = TYPEDSTREAM_ERROR_FORMAT;
00272 if ( GzFile )
00273 {
00274 gzclose( GzFile );
00275 GzFile = NULL;
00276 }
00277
00278 if ( File )
00279 {
00280 fclose( File );
00281 File = NULL;
00282 }
00283 return;
00284 }
00285 break;
00286
00287 case TYPEDSTREAM_WRITE:
00288 case TYPEDSTREAM_WRITE_ZLIB:
00289 if ( GzFile )
00290 gzprintf( GzFile, "%s\n", GetTypedStreamIdent() );
00291 else
00292 fprintf( File, "%s\n", GetTypedStreamIdent() );
00293 break;
00294
00295 case TYPEDSTREAM_APPEND:
00296 if ( GzFile )
00297 {
00298 if ( 0 == gztell( File) )
00299 gzprintf( GzFile, "%s\n", GetTypedStreamIdent() );
00300 }
00301 else
00302 if ( 0 == ftell( File) )
00303 fprintf( File, "%s\n", GetTypedStreamIdent() );
00304 break;
00305 }
00306 }
00307
00308 void
00309 TypedStream
00310 ::Close()
00311 {
00312 if ( File || GzFile )
00313 {
00314 if ( Mode == TYPEDSTREAM_WRITE || Mode == TYPEDSTREAM_APPEND )
00315 {
00316 while ( ! LevelStack.empty() )
00317 {
00318 LevelStack.pop();
00319 int streamLevel = LevelStack.size();
00320 if ( GzFile )
00321 {
00322 for ( int level = 0; level < streamLevel; level++)
00323 gzputs( GzFile, "\t" );
00324 gzputs( GzFile, "}\n" );
00325 }
00326 else
00327 {
00328 for ( int level = 0; level < streamLevel; level++)
00329 fputs( "\t", File );
00330 fputs( "}\n", File );
00331 }
00332 }
00333 }
00334 else
00335 {
00336 while ( ! LevelStack.empty() )
00337 {
00338 LevelStack.pop();
00339 }
00340 }
00341
00342 if ( GzFile )
00343 {
00344 gzclose( GzFile );
00345 GzFile = NULL;
00346 }
00347 if ( File )
00348 {
00349 fclose( File );
00350 File = NULL;
00351 }
00352 }
00353
00354 Status = TYPEDSTREAM_ERROR_NONE;
00355 SplitPosition = NULL;
00356 }
00357
00358 TypedStreamCondition
00359 TypedStream
00360 ::Begin
00361 ( const char* section )
00362 {
00363 if ( !File && !GzFile)
00364 {
00365 Status = TYPEDSTREAM_ERROR_INVALID;
00366 return TYPEDSTREAM_ERROR;
00367 }
00368
00369 if ( (Mode != TYPEDSTREAM_READ) && !section)
00370 {
00371 Status = TYPEDSTREAM_ERROR_ARG;
00372 return TYPEDSTREAM_ERROR;
00373 }
00374
00375 if ( Mode == TYPEDSTREAM_READ )
00376 {
00377 if ( GzFile )
00378 gzseek( GzFile, LevelStack.top(), SEEK_SET );
00379 else
00380 fseek( File, LevelStack.top(), SEEK_SET );
00381 return TYPEDSTREAM_OK;
00382 }
00383 else
00384 {
00385 int streamLevel = LevelStack.size();
00386 if ( GzFile )
00387 {
00388 for ( int level = 0; level < streamLevel; level++)
00389 gzputs( GzFile, "\t" );
00390
00391 gzprintf( GzFile, "%s {\n", section );
00392 }
00393 else
00394 {
00395 for ( int level = 0; level < streamLevel; level++)
00396 fputs( "\t", File );
00397
00398 fprintf( File, "%s {\n", section );
00399 }
00400
00401 if ( GzFile )
00402 LevelStack.push( gztell( GzFile ) );
00403 else
00404 LevelStack.push( ftell( File ) );
00405 }
00406
00407 return TYPEDSTREAM_OK;
00408 }
00409
00410 TypedStreamCondition
00411 TypedStream
00412 ::End
00413 ( const bool flush )
00414 {
00415 if ( ! File && ! GzFile )
00416 {
00417 Status = TYPEDSTREAM_ERROR_INVALID;
00418 return TYPEDSTREAM_ERROR;
00419 }
00420
00421 if ( Mode == TYPEDSTREAM_READ )
00422 {
00423 if ( LevelStack.size() == 0 )
00424 {
00425
00426 Status = TYPEDSTREAM_ERROR_LEVEL;
00427 return TYPEDSTREAM_ERROR;
00428 }
00429
00430 TypedStreamToken token;
00431 int currentLevel = 1;
00432 while ( currentLevel && (TYPEDSTREAM_EOF != ( token = this->ReadLineToken() ) ) )
00433 {
00434 if ( token == TYPEDSTREAM_BEGIN )
00435 {
00436 this->DebugOutput( "Skipping section %s at level %d.", BufferKey, currentLevel );
00437 ++currentLevel;
00438 }
00439 else
00440 if ( token == TYPEDSTREAM_END )
00441 {
00442 this->DebugOutput( "Leaving section %d.", currentLevel );
00443 --currentLevel;
00444 }
00445 }
00446
00447 LevelStack.pop();
00448 }
00449 else
00450 {
00451 int streamLevel = LevelStack.size();
00452 if ( streamLevel == 0 )
00453 {
00454
00455 Status = TYPEDSTREAM_ERROR_LEVEL;
00456 return TYPEDSTREAM_ERROR;
00457 }
00458
00459 LevelStack.pop();
00460 if ( GzFile )
00461 {
00462 for ( int level = 0; level < streamLevel-1; level++ )
00463 gzputs( GzFile, "\t" );
00464 gzputs( GzFile, "}\n" );
00465 }
00466 else
00467 {
00468 for ( int level = 0; level < streamLevel-1; level++ )
00469 fputs( "\t", File );
00470 fputs( "}\n", File );
00471 }
00472 }
00473
00474 if ( flush )
00475 {
00476 fflush( File );
00477 }
00478
00479 return TYPEDSTREAM_OK;
00480 }
00481
00482 TypedStreamCondition
00483 TypedStream
00484 ::Seek
00485 ( const char* section, const bool forward )
00486 {
00487 if ( ! File && ! GzFile )
00488 {
00489 Status = TYPEDSTREAM_ERROR_INVALID;
00490 return TYPEDSTREAM_ERROR;
00491 }
00492
00493 if ( ! section )
00494 {
00495 Status = TYPEDSTREAM_ERROR_ARG;
00496 return TYPEDSTREAM_ERROR;
00497 }
00498 if ( Mode != TYPEDSTREAM_READ )
00499 {
00500 Status = TYPEDSTREAM_ERROR_MODE;
00501 return TYPEDSTREAM_ERROR;
00502 }
00503
00504 unsigned initialLevel = LevelStack.size();
00505
00506 if ( ! forward )
00507 {
00508 if ( GzFile )
00509 {
00510 if ( initialLevel )
00511 {
00512 gzseek( GzFile, LevelStack.top(), SEEK_SET );
00513 }
00514 else
00515 {
00516 gzseek( GzFile, 0, SEEK_SET);
00517 }
00518 }
00519 else
00520 if ( initialLevel )
00521 {
00522 fseek( File, LevelStack.top(), SEEK_SET );
00523 }
00524 else
00525 {
00526 fseek( File, 0, SEEK_SET);
00527 }
00528 }
00529
00530 unsigned currentLevel = initialLevel;
00531
00532 this->DebugOutput( "Seeking section %s from level %d.", section, initialLevel );
00533 TypedStreamToken token;
00534 while ( TYPEDSTREAM_EOF != ( token = this->ReadLineToken() ) )
00535 {
00536 if ( token == TYPEDSTREAM_BEGIN )
00537 {
00538 this->DebugOutput( "Enter section %s at level %d.", BufferKey, currentLevel );
00539 if ( this->StringCmp( BufferKey, section ) == 0 )
00540 {
00541 if ( currentLevel == LevelStack.size() )
00542 {
00543 if ( GzFile )
00544 LevelStack.push( gztell( GzFile ) );
00545 else
00546 LevelStack.push( ftell( File ) );
00547 return TYPEDSTREAM_OK;
00548 }
00549 if ( currentLevel == LevelStack.size()-1 )
00550 {
00551 LevelStack.pop();
00552 if ( GzFile )
00553 LevelStack.push( gztell( GzFile ) );
00554 else
00555 LevelStack.push( ftell( File ) );
00556 return TYPEDSTREAM_OK;
00557 }
00558 }
00559 ++ currentLevel;
00560 }
00561 if ( token == TYPEDSTREAM_END )
00562 {
00563 this->DebugOutput( "Leaving section %d.", currentLevel );
00564 if ( ! currentLevel )
00565 {
00566 Status = TYPEDSTREAM_ERROR_LEVEL;
00567 return TYPEDSTREAM_ERROR;
00568 }
00569 if ( currentLevel < initialLevel )
00570 {
00571 Status = TYPEDSTREAM_ERROR_NONE;
00572 return TYPEDSTREAM_ERROR;
00573 }
00574 -- currentLevel;
00575 }
00576 }
00577
00578 this->DebugOutput( "Section %s not found.", section );
00579 Status = TYPEDSTREAM_ERROR_NONE;
00580 return TYPEDSTREAM_ERROR;
00581 }
00582
00583 TypedStreamCondition
00584 TypedStream
00585 ::Rewind()
00586 {
00587 if ( ! File && ! GzFile )
00588 {
00589 Status = TYPEDSTREAM_ERROR_INVALID;
00590 return TYPEDSTREAM_ERROR;
00591 }
00592 if ( Mode != TYPEDSTREAM_READ )
00593 {
00594 Status = TYPEDSTREAM_ERROR_MODE;
00595 return TYPEDSTREAM_ERROR;
00596 }
00597
00598 if ( LevelStack.size() )
00599 LevelStack.pop();
00600
00601 if ( LevelStack.size() == 0 )
00602 {
00603 if ( GzFile )
00604 {
00605 if ( -1 == gzseek( GzFile, 0, SEEK_SET ) )
00606 {
00607 Status = TYPEDSTREAM_ERROR_SYSTEM;
00608 return TYPEDSTREAM_ERROR;
00609 }
00610 }
00611 else
00612 if ( -1 == fseek( File, 0, SEEK_SET ) )
00613 {
00614 Status = TYPEDSTREAM_ERROR_SYSTEM;
00615 return TYPEDSTREAM_ERROR;
00616 }
00617 }
00618 else
00619 {
00620 if ( GzFile )
00621 {
00622 if (-1 == gzseek( GzFile, LevelStack.top(), SEEK_SET))
00623 {
00624 Status = TYPEDSTREAM_ERROR_SYSTEM;
00625 return TYPEDSTREAM_ERROR;
00626 }
00627 }
00628 else
00629 if (-1 == fseek( File, LevelStack.top(), SEEK_SET))
00630 {
00631 Status = TYPEDSTREAM_ERROR_SYSTEM;
00632 return TYPEDSTREAM_ERROR;
00633 }
00634 }
00635 return TYPEDSTREAM_OK;
00636 }
00637
00638 bool
00639 TypedStream
00640 ::ReadBool( const char* key, const bool defaultValue, const bool forward )
00641 {
00642 int value;
00643
00644 if ( this->GenericReadArray( key, TYPEDSTREAM_TYPE_BOOL, &value, 1, forward ) != TYPEDSTREAM_OK )
00645 if ( this->GenericReadArray( key, TYPEDSTREAM_TYPE_INT, &value, 1, forward ) != TYPEDSTREAM_OK )
00646 return defaultValue;
00647
00648 return (value != 0);
00649 }
00650
00651 TypedStreamCondition
00652 TypedStream
00653 ::ReadBoolArray( const char* key, byte *const array, const int size, const bool forward )
00654 {
00655 return this->GenericReadArray( key, TYPEDSTREAM_TYPE_BINARYBOOL, array, size, forward );
00656 }
00657
00658 int
00659 TypedStream
00660 ::ReadInt( const char* key, const int defaultValue, const bool forward )
00661 {
00662 int value = defaultValue;
00663 if ( this->GenericReadArray( key, TYPEDSTREAM_TYPE_INT, &value, 1, forward ) != TYPEDSTREAM_OK )
00664 return defaultValue;
00665
00666 return value;
00667 }
00668
00669 TypedStreamCondition
00670 TypedStream
00671 ::ReadIntArray( const char* key, int *const array, const int size, const bool forward )
00672 {
00673 return this->GenericReadArray( key, TYPEDSTREAM_TYPE_INT, array, size, forward );
00674 }
00675
00676 float
00677 TypedStream
00678 ::ReadFloat( const char* key, const float defaultValue, const bool forward )
00679 {
00680 float value = defaultValue;
00681 if ( this->GenericReadArray( key, TYPEDSTREAM_TYPE_FLOAT, &value, 1, forward ) != TYPEDSTREAM_OK )
00682 return defaultValue;
00683
00684 return value;
00685 }
00686
00687 TypedStreamCondition
00688 TypedStream
00689 ::ReadFloatArray( const char* key, float *const array, const int size, const bool forward )
00690 {
00691 return this->GenericReadArray( key, TYPEDSTREAM_TYPE_FLOAT, array, size, forward );
00692 }
00693
00694 double
00695 TypedStream
00696 ::ReadDouble( const char* key, const double defaultValue, const bool forward )
00697 {
00698 double value = defaultValue;
00699 if ( this->GenericReadArray( key, TYPEDSTREAM_TYPE_DOUBLE, &value, 1, forward ) != TYPEDSTREAM_OK )
00700 return defaultValue;
00701
00702 return value;
00703 }
00704
00705 TypedStreamCondition
00706 TypedStream
00707 ::ReadDoubleArray( const char* key, double *const array, const int size, const bool forward )
00708 {
00709 return this->GenericReadArray( key, TYPEDSTREAM_TYPE_DOUBLE, array, size, forward );
00710 }
00711
00712 char*
00713 TypedStream
00714 ::ReadString( const char* key, const char *defaultValue, const bool forward )
00715 {
00716 char *value;
00717 if ( this->GenericReadArray( key, TYPEDSTREAM_TYPE_STRING, &value, 1, forward ) != TYPEDSTREAM_OK )
00718 {
00719 if ( defaultValue )
00720 return strdup( defaultValue );
00721 else
00722 return NULL;
00723 }
00724
00725 return value;
00726 }
00727
00728 TypedStreamCondition
00729 TypedStream
00730 ::WriteBool( const char* key, const bool value )
00731 {
00732 int currentLevel = LevelStack.size();
00733 if ( GzFile )
00734 {
00735 for ( int level = 0; level < currentLevel; level++ )
00736 gzputs( GzFile, "\t" );
00737 gzprintf( GzFile, "%s %s\n", key, (value) ? "yes" : "no");
00738 }
00739 else
00740 {
00741 for ( int level = 0; level < currentLevel; level++ )
00742 fputs( "\t", File );
00743 fprintf( File, "%s %s\n", key, (value) ? "yes" : "no");
00744 }
00745 return TYPEDSTREAM_OK;
00746 }
00747
00748 TypedStreamCondition
00749 TypedStream
00750 ::WriteInt( const char* key, const int value )
00751 {
00752 int currentLevel = LevelStack.size();
00753 if ( GzFile )
00754 {
00755 for ( int level = 0; level < currentLevel; level++ )
00756 gzputs( GzFile, "\t" );
00757 gzprintf( GzFile, "%s %d\n", key, value );
00758 }
00759 else
00760 {
00761 for ( int level = 0; level < currentLevel; level++ )
00762 fputs( "\t", File );
00763 fprintf( File, "%s %d\n", key, value );
00764 }
00765 return TYPEDSTREAM_OK;
00766 }
00767
00768 TypedStreamCondition
00769 TypedStream
00770 ::WriteFloat( const char* key, const float value )
00771 {
00772 int currentLevel = LevelStack.size();
00773 if ( GzFile )
00774 {
00775 for ( int level = 0; level < currentLevel; level++ )
00776 gzputs( GzFile, "\t" );
00777 gzprintf( GzFile, "%s %.*f\n", key, PrecisionFloat, value );
00778 }
00779 else
00780 {
00781 for ( int level = 0; level < currentLevel; level++ )
00782 fputs( "\t", File );
00783 fprintf( File, "%s %.*f\n", key, PrecisionFloat, value );
00784 }
00785 return TYPEDSTREAM_OK;
00786 }
00787
00788 TypedStreamCondition
00789 TypedStream
00790 ::WriteDouble( const char* key, const double value )
00791 {
00792 int currentLevel = LevelStack.size();
00793 if ( GzFile )
00794 {
00795 for ( int level = 0; level < currentLevel; level++ )
00796 gzputs( GzFile, "\t" );
00797 gzprintf( File, "%s %.*f\n", key, PrecisionDouble, value );
00798 }
00799 else
00800 {
00801 for ( int level = 0; level < currentLevel; level++ )
00802 fputs( "\t", File );
00803 fprintf( File, "%s %.*f\n", key, PrecisionDouble, value );
00804 }
00805 return TYPEDSTREAM_OK;
00806 }
00807
00808 TypedStreamCondition
00809 TypedStream
00810 ::WriteString( const char* key, const std::string& value )
00811 {
00812 return this->WriteString( key, value.c_str() );
00813 }
00814
00815 TypedStreamCondition
00816 TypedStream
00817 ::WriteString( const char* key, const char* value )
00818 {
00819 char *buffer = Buffer;
00820
00821 const char *strValue = (value) ? value : "";
00822 while (*strValue)
00823 {
00824 if (*strValue == '\\')
00825 {
00826 *buffer++ = '\\';
00827 *buffer++ = *strValue++;
00828 continue;
00829 }
00830 if (*strValue == '\"')
00831 {
00832 *buffer++ = '\\';
00833 *buffer++ = *strValue++;
00834 continue;
00835 }
00836 if (*strValue == '\n')
00837 {
00838 *buffer++ = '\\';
00839 *buffer++ = 'n';
00840 strValue++;
00841 continue;
00842 }
00843 *buffer++ = *strValue++;
00844 }
00845
00846 *buffer++ = '\0';
00847
00848 int currentLevel = LevelStack.size();
00849 if ( GzFile )
00850 {
00851 for ( int level = 0; level < currentLevel; level++)
00852 gzputs( GzFile, "\t" );
00853 gzprintf( GzFile, "%s \"%s\"\n", key, Buffer);
00854 }
00855 else
00856 {
00857 for ( int level = 0; level < currentLevel; level++)
00858 fputs( "\t", File );
00859 fprintf( File, "%s \"%s\"\n", key, Buffer);
00860 }
00861
00862 return TYPEDSTREAM_OK;
00863 }
00864
00865 TypedStreamCondition
00866 TypedStream
00867 ::WriteComment( const char* fmt, ... )
00868 {
00869 if ( this->Mode != TYPEDSTREAM_WRITE )
00870 {
00871 Status = TYPEDSTREAM_ERROR_MODE;
00872 return TYPEDSTREAM_ERROR;
00873 }
00874
00875 static char buffer[1024];
00876
00877 va_list args;
00878 va_start(args, fmt);
00879 vsnprintf( buffer, sizeof( buffer ), fmt, args );
00880 va_end(args);
00881
00882 if ( this->GzFile )
00883 gzprintf( GzFile, "! %s\n", buffer );
00884 else
00885 fprintf( File, "! %s\n", buffer );
00886
00887 return TYPEDSTREAM_OK;
00888 }
00889
00890 TypedStreamCondition
00891 TypedStream
00892 ::WriteComment( int argc, char* argv[] )
00893 {
00894 return this->WriteComment( argc, const_cast<const char**>( argv ) );
00895 }
00896
00897 TypedStreamCondition
00898 TypedStream
00899 ::WriteComment( const int argc, const char* argv[] )
00900 {
00901 if ( this->Mode != TYPEDSTREAM_WRITE )
00902 {
00903 Status = TYPEDSTREAM_ERROR_MODE;
00904 return TYPEDSTREAM_ERROR;
00905 }
00906
00907 if ( this->GzFile )
00908 gzprintf( GzFile, "! " );
00909 else
00910 fprintf( File, "! " );
00911
00912 for ( int i = 0; i < argc; ++i )
00913 {
00914 if ( this->GzFile )
00915 gzprintf( GzFile, "%s ", argv[i] );
00916 else
00917 fprintf( File, "%s ", argv[i] );
00918 }
00919
00920 if ( this->GzFile )
00921 gzputs( GzFile, "\n" );
00922 else
00923 fputs( "\n", File );
00924
00925 return TYPEDSTREAM_OK;
00926 }
00927
00928 TypedStreamCondition
00929 TypedStream
00930 ::WriteIntArray( const char* key, const int* array, const int size, const int valuesPerLine )
00931 {
00932 if ( !array || size < 1)
00933 {
00934 Status = TYPEDSTREAM_ERROR_ARG;
00935 return TYPEDSTREAM_ERROR;
00936 }
00937
00938 int currentLevel = LevelStack.size();
00939 if ( GzFile )
00940 {
00941 for ( int level = 0; level < currentLevel; level++)
00942 gzputs( GzFile, "\t" );
00943
00944 gzprintf( File, "%s ", key );
00945
00946 for ( int i = 0; i < size; i++)
00947 {
00948 if (i && (i % valuesPerLine) == 0)
00949 {
00950 gzprintf( GzFile, "\n\t");
00951 for ( int level = 0; level < currentLevel; level++ )
00952 gzputs( GzFile, "\t" );
00953 }
00954 gzprintf( GzFile, "%d ", array[i] );
00955 }
00956
00957 gzputs( GzFile, "\n" );
00958 }
00959 else
00960 {
00961 for ( int level = 0; level < currentLevel; level++)
00962 fputs( "\t", File );
00963
00964 fprintf( File, "%s ", key );
00965
00966 for ( int i = 0; i < size; i++)
00967 {
00968 if (i && (i % valuesPerLine) == 0)
00969 {
00970 fprintf( File, "\n\t");
00971 for ( int level = 0; level < currentLevel; level++ )
00972 fputs( "\t", File );
00973 }
00974 fprintf( File, "%d ", array[i] );
00975 }
00976
00977 fputs( "\n", File);
00978 }
00979
00980 return TYPEDSTREAM_OK;
00981 }
00982
00983 TypedStreamCondition
00984 TypedStream
00985 ::WriteBoolArray( const char* key, const byte* array, const int size, const int valuesPerLine )
00986 {
00987 if ( !array || size < 1)
00988 {
00989 Status = TYPEDSTREAM_ERROR_ARG;
00990 return TYPEDSTREAM_ERROR;
00991 }
00992
00993 int currentLevel = LevelStack.size();
00994 if ( GzFile )
00995 {
00996 for ( int level = 0; level < currentLevel; level++)
00997 gzputs( GzFile, "\t" );
00998
00999 gzprintf( GzFile, "%s ", key );
01000
01001 for ( int i = 0; i < size; i++)
01002 {
01003 if (i && (i % valuesPerLine) == 0)
01004 {
01005 gzprintf( GzFile, "\n\t");
01006 for ( int level = 0; level < currentLevel; level++ )
01007 gzputs( GzFile, "\t" );
01008 }
01009 gzprintf( GzFile, "%d", (array[i/8]>>(i%8))&1 );
01010 }
01011
01012 gzputs( GzFile, "\n" );
01013 }
01014 else
01015 {
01016 for ( int level = 0; level < currentLevel; level++)
01017 fputs( "\t", File );
01018
01019 fprintf( File, "%s ", key );
01020
01021 for ( int i = 0; i < size; i++)
01022 {
01023 if (i && (i % valuesPerLine) == 0)
01024 {
01025 fprintf( File, "\n\t");
01026 for ( int level = 0; level < currentLevel; level++ )
01027 fputs( "\t", File );
01028 }
01029 fprintf( File, "%d", (array[i/8]>>(i%8))&1 );
01030 }
01031
01032 fputs( "\n", File );
01033 }
01034
01035 return TYPEDSTREAM_OK;
01036 }
01037
01038 TypedStreamCondition
01039 TypedStream
01040 ::WriteFloatArray( const char* key, const float* array, const int size, const int valuesPerLine )
01041 {
01042 if ( !array || size < 1)
01043 {
01044 Status = TYPEDSTREAM_ERROR_ARG;
01045 return TYPEDSTREAM_ERROR;
01046 }
01047
01048 int currentLevel = LevelStack.size();
01049 if ( GzFile )
01050 {
01051 for ( int level = 0; level < currentLevel; level++)
01052 gzputs( GzFile, "\t" );
01053
01054 gzprintf( GzFile, "%s ", key );
01055
01056 for ( int i = 0; i < size; i++ )
01057 {
01058 if (i && (i % valuesPerLine) == 0)
01059 {
01060 gzprintf( GzFile, "\n\t");
01061 for ( int level = 0; level < currentLevel; level++ )
01062 gzputs( GzFile, "\t" );
01063 }
01064 gzprintf( GzFile, "%.*g ", PrecisionFloat, array[i] );
01065 }
01066
01067 gzprintf( GzFile, "\n" );
01068 }
01069 else
01070 {
01071 for ( int level = 0; level < currentLevel; level++)
01072 fputs( "\t", File );
01073
01074 fprintf( File, "%s ", key );
01075
01076 for ( int i = 0; i < size; i++ )
01077 {
01078 if (i && (i % valuesPerLine) == 0)
01079 {
01080 fprintf( File, "\n\t");
01081 for ( int level = 0; level < currentLevel; level++ )
01082 fputs( "\t", File );
01083 }
01084 fprintf( File, "%.*g ", PrecisionFloat, array[i] );
01085 }
01086
01087 fprintf( File, "\n" );
01088 }
01089
01090 return TYPEDSTREAM_OK;
01091 }
01092
01093 TypedStreamCondition
01094 TypedStream
01095 ::WriteDoubleArray( const char* key, const double* array, const int size, const int valuesPerLine )
01096 {
01097 if ( !array || size < 1)
01098 {
01099 Status = TYPEDSTREAM_ERROR_ARG;
01100 return TYPEDSTREAM_ERROR;
01101 }
01102
01103 int currentLevel = LevelStack.size();
01104 if ( GzFile )
01105 {
01106 for ( int level = 0; level < currentLevel; level++)
01107 gzputs( GzFile, "\t" );
01108
01109 gzprintf( GzFile, "%s ", key );
01110
01111 for ( int i = 0; i < size; i++ )
01112 {
01113 if (i && (i % valuesPerLine) == 0)
01114 {
01115 gzprintf( GzFile, "\n\t");
01116 for ( int level = 0; level < currentLevel; level++ )
01117 gzputs( GzFile, "\t" );
01118 }
01119 gzprintf( GzFile, "%.*g ", PrecisionDouble, array[i] );
01120 }
01121
01122 gzprintf( GzFile, "\n" );
01123 }
01124 else
01125 {
01126 for ( int level = 0; level < currentLevel; level++)
01127 fputs( "\t", File );
01128
01129 fprintf( File, "%s ", key );
01130
01131 for ( int i = 0; i < size; i++ )
01132 {
01133 if (i && (i % valuesPerLine) == 0)
01134 {
01135 fprintf( File, "\n\t");
01136 for ( int level = 0; level < currentLevel; level++ )
01137 fputs( "\t", File );
01138 }
01139 fprintf( File, "%.*g ", PrecisionDouble, array[i] );
01140 }
01141
01142 fprintf( File, "\n" );
01143 }
01144
01145 return TYPEDSTREAM_OK;
01146 }
01147
01148 TypedStreamCondition
01149 TypedStream
01150 ::GenericReadArray( const char * key, const int type, void *const array, const int arraySize, const bool forward )
01151 {
01152 if (!array || arraySize < 1)
01153 {
01154 Status = TYPEDSTREAM_ERROR_ARG;
01155 return TYPEDSTREAM_ERROR;
01156 }
01157
01158 unsigned currentLevel = LevelStack.size();
01159 if ( ! forward )
01160 {
01161 if ( GzFile )
01162 {
01163 if ( currentLevel )
01164 gzseek( GzFile, LevelStack.top(), SEEK_SET );
01165 else
01166 gzseek( GzFile, 0, SEEK_SET );
01167 }
01168 else
01169 if ( currentLevel )
01170 fseek( File, LevelStack.top(), SEEK_SET );
01171 else
01172 fseek( File, 0, SEEK_SET );
01173 }
01174
01175 int line;
01176 char *buffer;
01177 while ( TYPEDSTREAM_EOF != ( line = this->ReadLineToken() ) )
01178 {
01179 if ( line == TYPEDSTREAM_KEY)
01180 {
01181 if ( (currentLevel == LevelStack.size()) && (this->StringCmp( BufferKey, key )) == 0 )
01182 {
01183 int i = 0;
01184 switch (type)
01185 {
01186 case TYPEDSTREAM_TYPE_INT:
01187 {
01188 int *arrayInt = static_cast<int*>( array );
01189 do
01190 {
01191 buffer = strtok( BufferValue, "\t\n " );
01192 while ( buffer )
01193 {
01194 if ( *buffer == '\"' )
01195 {
01196 Status = TYPEDSTREAM_ERROR_TYPE;
01197 return TYPEDSTREAM_ERROR;
01198 }
01199 if ( i >= arraySize )
01200 return TYPEDSTREAM_OK;
01201 arrayInt[i++] = atoi(buffer);
01202 buffer = strtok( NULL, "\t\n " );
01203 }
01204 } while ( i < arraySize && TYPEDSTREAM_VALUE == this->ReadLineToken() );
01205 if ( i < arraySize)
01206 {
01207 Status = TYPEDSTREAM_ERROR_ARG;
01208 return TYPEDSTREAM_ERROR;
01209 }
01210 break;
01211 }
01212 case TYPEDSTREAM_TYPE_BOOL:
01213 {
01214 int *arrayInt = static_cast<int*>( array );
01215 if (arraySize != 1)
01216 {
01217 Status = TYPEDSTREAM_ERROR_ARG;
01218 return TYPEDSTREAM_ERROR;
01219 }
01220 do
01221 {
01222 buffer = strtok( BufferValue, "\t\n " );
01223 while ( buffer )
01224 {
01225 if ( i >= arraySize )
01226 return TYPEDSTREAM_OK;
01227 if ((buffer[0] == 'y' || buffer[0] == 'Y') &&
01228 (buffer[1] == 'e' || buffer[1] == 'E') &&
01229 (buffer[2] == 's' || buffer[2] == 'S'))
01230 {
01231 arrayInt[i++] = 1;
01232 }
01233 else
01234 {
01235 arrayInt[i++] = 0;
01236 }
01237 buffer = strtok( NULL, "\t\n " );
01238 }
01239 } while ( i < arraySize && TYPEDSTREAM_VALUE == this->ReadLineToken() );
01240 if ( i < arraySize )
01241 {
01242 Status = TYPEDSTREAM_ERROR_ARG;
01243 return TYPEDSTREAM_ERROR;
01244 }
01245 break;
01246 }
01247 case TYPEDSTREAM_TYPE_BINARYBOOL:
01248 {
01249 byte *arrayInt = static_cast<byte*>( array );
01250 do
01251 {
01252 buffer = strtok( BufferValue, "\t\n " );
01253 int idx = 0;
01254 while ( (buffer[idx]=='0') || (buffer[idx]=='1') )
01255 {
01256 if ( i >= arraySize )
01257 return TYPEDSTREAM_OK;
01258 if ( buffer[idx] == '0' )
01259 arrayInt[i/8] &= ~(1<<(i%8));
01260 else
01261 arrayInt[i/8] |= (1<<(i%8));
01262 ++i;
01263 ++idx;
01264 }
01265 } while ( i < arraySize && TYPEDSTREAM_VALUE == this->ReadLineToken() );
01266 if ( i < arraySize )
01267 {
01268 Status = TYPEDSTREAM_ERROR_ARG;
01269 return TYPEDSTREAM_ERROR;
01270 }
01271 break;
01272 }
01273 case TYPEDSTREAM_TYPE_FLOAT:
01274 {
01275 float *arrayFloat = static_cast<float*>( array );
01276 do
01277 {
01278 buffer = strtok( BufferValue, "\t\n " );
01279 while ( buffer )
01280 {
01281 if ( *buffer == '\"' )
01282 {
01283 Status = TYPEDSTREAM_ERROR_TYPE;
01284 return TYPEDSTREAM_ERROR;
01285 }
01286 if ( i >= arraySize )
01287 return TYPEDSTREAM_OK;
01288 arrayFloat[i++] = static_cast<float>( atof( buffer ) );
01289 buffer = strtok( NULL, "\t\n " );
01290 }
01291 } while ( i < arraySize && TYPEDSTREAM_VALUE == this->ReadLineToken() );
01292 if ( i < arraySize )
01293 {
01294 Status = TYPEDSTREAM_ERROR_ARG;
01295 return TYPEDSTREAM_ERROR;
01296 }
01297 break;
01298 }
01299 case TYPEDSTREAM_TYPE_DOUBLE:
01300 {
01301 double *arrayDouble = static_cast<double*>( array );
01302 do
01303 {
01304 buffer = strtok( BufferValue, "\t\n " );
01305 while ( buffer )
01306 {
01307 if ( *buffer == '\"' )
01308 {
01309 Status = TYPEDSTREAM_ERROR_TYPE;
01310 return TYPEDSTREAM_ERROR;
01311 }
01312 if ( i >= arraySize )
01313 return TYPEDSTREAM_OK;
01314 arrayDouble[i++] = atof( buffer );
01315 buffer = strtok( NULL, "\t\n " );
01316 }
01317 } while ( i < arraySize && TYPEDSTREAM_VALUE == this->ReadLineToken() );
01318 if ( i < arraySize )
01319 {
01320 Status = TYPEDSTREAM_ERROR_ARG;
01321 return TYPEDSTREAM_ERROR;
01322 }
01323 break;
01324 }
01325 case TYPEDSTREAM_TYPE_STRING:
01326 {
01327 char **arrayString = static_cast<char**>( array );
01328 do
01329 {
01330 buffer = this->StringSplit( BufferValue );
01331 while ( buffer )
01332 {
01333 if ( i >= arraySize )
01334 return TYPEDSTREAM_OK;
01335 if ( *buffer != '\"' )
01336 {
01337 Status = TYPEDSTREAM_ERROR_TYPE;
01338 return TYPEDSTREAM_ERROR;
01339 }
01340 char *b;
01341 if (!(b = (char *)malloc(strlen(buffer))))
01342 {
01343 for (--i; i >= 0; i--)
01344 free( arrayString[i] );
01345 Status = TYPEDSTREAM_ERROR_SYSTEM;
01346 return TYPEDSTREAM_ERROR;
01347 }
01348 arrayString[i++] = b;
01349 buffer++;
01350 for (; *buffer && *buffer != '\n'; buffer++)
01351 {
01352 if (*buffer == '\"')
01353 continue;
01354 if (*buffer == '\\')
01355 {
01356 buffer++;
01357 if (*buffer == 'n')
01358 {
01359 *b++ = '\n';
01360 continue;
01361 }
01362 if (*buffer == 't')
01363 {
01364 *b++ = '\t';
01365 continue;
01366 }
01367 if (*buffer == '\0')
01368 break;
01369 }
01370 *b++ = *buffer;
01371 }
01372 *b = '\0';
01373 buffer = this->StringSplit( NULL );
01374 }
01375 } while ( i < arraySize && TYPEDSTREAM_VALUE == this->ReadLineToken() );
01376 if ( i < arraySize )
01377 {
01378 for (--i; i >= 0; i--)
01379 free( arrayString[i] );
01380 Status = TYPEDSTREAM_ERROR_ARG;
01381 return TYPEDSTREAM_ERROR;
01382 }
01383 break;
01384 }
01385 }
01386 return TYPEDSTREAM_OK;
01387 }
01388 continue;
01389 }
01390 if ( line == TYPEDSTREAM_BEGIN )
01391 {
01392 if ( GzFile )
01393 LevelStack.push( gztell( GzFile ) );
01394 else
01395 LevelStack.push( ftell( File ) );
01396 continue;
01397 }
01398 if ( line == TYPEDSTREAM_END )
01399 {
01400 if ( currentLevel == LevelStack.size() )
01401 {
01402 Status = TYPEDSTREAM_ERROR_NONE;
01403 return TYPEDSTREAM_ERROR;
01404 }
01405 LevelStack.pop();
01406 continue;
01407 }
01408 }
01409
01410 return TYPEDSTREAM_ERROR;
01411 }
01412
01413 TypedStreamToken
01414 TypedStream
01415 ::ReadLineToken()
01416 {
01417 if ( GzFile )
01418 {
01419 if (! gzgets( GzFile, Buffer, TYPEDSTREAM_LIMIT_BUFFER ) )
01420 return TYPEDSTREAM_EOF;
01421 }
01422 else
01423 if (! fgets( Buffer, TYPEDSTREAM_LIMIT_BUFFER, File ) )
01424 return TYPEDSTREAM_EOF;
01425
01426 char* buffer;
01427 for ( buffer = Buffer; *buffer; buffer++)
01428 if (*buffer != ' ' && *buffer != '\t')
01429 break;
01430
01431 if (*buffer == '\n' || *buffer == '!' || *buffer == '#')
01432 return TYPEDSTREAM_COMMENT;
01433
01434 if (*buffer == '}')
01435 return TYPEDSTREAM_END;
01436
01437 if (*buffer == '\"' || *buffer == '-' || *buffer == '.' || (*buffer >= '0' && *buffer <= '9'))
01438 {
01439 BufferValue = buffer;
01440 return TYPEDSTREAM_VALUE;
01441 }
01442
01443 if (*buffer == '_' || (*buffer >= 'a' && *buffer <= 'z') || (*buffer >= 'A' && *buffer <= 'Z'))
01444 {
01445 BufferKey = buffer;
01446 for (; *buffer; buffer++)
01447 if (*buffer == ' ' || *buffer == '\t')
01448 break;
01449 for (; *buffer; buffer++)
01450 if (*buffer != ' ' && *buffer != '\t')
01451 break;
01452 BufferValue = buffer;
01453 if (*buffer == '{')
01454 return TYPEDSTREAM_BEGIN;
01455
01456 return TYPEDSTREAM_KEY;
01457 }
01458
01459 return TYPEDSTREAM_COMMENT;
01460 }
01461
01462 int
01463 TypedStream
01464 ::StringCmp( const char *s1, const char *s2 )
01465 {
01466 for (; *s1 && *s2; s1++, s2++)
01467 {
01468 if (*s1 == ' ' || *s1 == '\t' || *s1 == '\n' || *s2 == ' ' || *s2 == '\t' || *s2 == '\n')
01469 {
01470 break;
01471 }
01472 if (*s1 == *s2)
01473 continue;
01474 if (*s1 >= 'a' && *s1 <= 'z')
01475 {
01476 if (*s1 - ('a'-'A') == *s2)
01477 continue;
01478 }
01479 if (*s2 >= 'a' && *s2 <= 'z')
01480 {
01481 if (*s2 - ('a'-'A') == *s1)
01482 continue;
01483 }
01484 return 1;
01485 }
01486
01487 if ((*s1 == ' ' || *s1 == '\0' || *s1 == '\t' || *s1 == '\n') && (*s2 == ' ' || *s2 == '\0' || *s2 == '\t' || *s2 == '\n'))
01488 {
01489 return 0;
01490 }
01491
01492 return 1;
01493 }
01494
01495 char*
01496 TypedStream
01497 ::StringSplit( char * s1 ) const
01498 {
01499 if (s1)
01500 SplitPosition = s1-1;
01501 if (SplitPosition == NULL)
01502 return NULL;
01503
01504
01505 for ( SplitPosition++; *SplitPosition == '\0' || *SplitPosition == ' ' ||
01506 *SplitPosition == '\t' || *SplitPosition == '\n'; SplitPosition++ )
01507 if ( *SplitPosition == '\0' )
01508 return NULL;
01509
01510 s1 = SplitPosition;
01511
01512
01513 if ( *SplitPosition == '\"' )
01514 {
01515
01516 for ( SplitPosition++; *SplitPosition && *SplitPosition != '\n' && *SplitPosition != '\t'; SplitPosition++)
01517 {
01518 if ( *SplitPosition == '\\' && *(SplitPosition+1) )
01519 {
01520 SplitPosition++;
01521 continue;
01522 }
01523 if ( *SplitPosition == '\"' )
01524 {
01525 SplitPosition++;
01526 break;
01527 }
01528 }
01529 }
01530 else
01531 {
01532
01533 for ( ; *SplitPosition; SplitPosition++ )
01534 {
01535 if ( *SplitPosition == ' ' || *SplitPosition == '\t' || *SplitPosition == '\n')
01536 break;
01537 }
01538 }
01539
01540 if ( *SplitPosition )
01541 {
01542 *SplitPosition = '\0';
01543 }
01544 else
01545 {
01546 SplitPosition = NULL;
01547 }
01548
01549 return s1;
01550 }
01551
01552 void
01553 TypedStream
01554 ::DebugOutput( const char* format, ... )
01555 {
01556 if ( DebugFlag != TYPEDSTREAM_DEBUG_ON ) return;
01557
01558 static char buffer[1024];
01559
01560 va_list args;
01561 va_start(args, format);
01562 vsnprintf( buffer, sizeof( buffer ), format, args );
01563 va_end(args);
01564
01565 fputs( buffer, stderr );
01566 fputs( "\n", stderr );
01567 }
01568
01569 }