// $Revision: 1.7 $ // Copyright (C) 1994-1995 Taligent, Inc. All rights reserved. #ifndef TaligentSamples_STREAMINGSNIPPETS #include "StreamingSnippets.h" #endif // For TMemorySurrogate et al. #ifndef Taligent_MEMORY #include #endif // For TStandardText. #ifndef Taligent_STANDARDTEXT #include #endif // For MGraphic et al. #ifndef Taligent_GRAPHICS #include #endif TaligentTypeExtensionMacro(TStreamingSnippets) TStreamingSnippets::TStreamingSnippets() : TSnippets() { SNIPPETINFO(ZeroABuffer); SNIPPETINFO(StreamToABuffer); SNIPPETINFO(StreamToHeap); SNIPPETINFO(StreamToHeapAndRead); SNIPPETINFO(FlattenToHeapAndResurrect); SNIPPETINFO(UsingFreezeLevels); SNIPPETINFO(StreamUsingContext); SNIPPETINFO(StreamingVersions); } TStreamingSnippets::~TStreamingSnippets() { } // Display utilities. void TStreamingSnippets::DisplayGraphic(const MGraphic* graphic) { // Display the name and address of the graphic. GetDisplay() << "name: " << DynamicTypeInfo(*graphic).name() << ", address: " << TRepData(&graphic, sizeof(MGraphic*), 4) << endl; } void TStreamingSnippets::DisplayData(void* data, unsigned long length) { // Display the length and contents of the data. GetDisplay() << "length: " << length << ", data: " << endl << TRepData(data, length) << endl; } // Use a memory surrogate to reference memory on the stack and zero it. void TStreamingSnippets::ZeroABuffer() { static const size_t kBufferSize = 40; unsigned char buffer[kBufferSize]; GetDisplay() << TRepData(buffer, kBufferSize) << endl; //- TMemorySurrogate(buffer, kBufferSize).FillWithZeros(); //- GetDisplay() << TRepData(buffer, kBufferSize) << endl; } // Use streaming operations to reference memory on the stack. // An exception will be thrown if the data to be streamed is larger than the // buffer can hold. For illustration this streams a TStandardText into a // buffer too small to hold it. void TStreamingSnippets::StreamToABuffer() { static const size_t kBufferSize = 20; unsigned char buffer[kBufferSize]; const TStandardText text("Sample text to stream."); GetDisplay() << text << endl; //- TContiguousMemoryStream stream(TMemorySurrogate(buffer, kBufferSize)); try { text >>= stream; } catch (const TStreamException& exception) { if (exception.GetReason() == TStreamException::kHitPhysicalEndOfStream) { GetDisplay() << "stream exception: hit physical end of stream" << endl; } else { throw exception; } } //- DisplayData(buffer, stream.GetLogicalEndOfStream()); } // Stream an object to a growable heap. Note you may still get an insufficient // memory exception, but in that case you are probably in too much trouble to do // anything about it. void TStreamingSnippets::StreamToHeap() { const TStandardText text("Sample text to stream."); GetDisplay() << text << endl; //- TContiguousGrowingStream stream; text >>= stream; //- TMemorySurrogate buffer; stream.GetMemorySurrogate(buffer); DisplayData(buffer.GetStartAddress(), stream.GetLogicalEndOfStream()); } // Stream an object to the current heap, and read it back from the heap. // This is nonpolymorphic-- you must read in exactly the same class that // was streamed out. void TStreamingSnippets::StreamToHeapAndRead() { const TStandardText text("Sample text to stream."); GetDisplay() << text << endl; //- TGrowingChunkyStream stream(new THeapChunkyMemory()); text >>= stream; stream.Seek(0); TStandardText readText; readText <<= stream; //- GetDisplay() << readText << endl; } // Polymorphically stream two objects to the current heap, and resurrect them // from the heap. This uses TLine and TEllipse, two subclasses of MGraphic, // to illustrate the polymorphism. void TStreamingSnippets::FlattenToHeapAndResurrect() { //- TGrowingChunkyStream stream(new THeapChunkyMemory()); const TLine line(TGPoint(0, 0), TGPoint(100, 100)); const TEllipse ellipse(TGRect(10, 10, 300, 200)); DisplayGraphic(&line); DisplayGraphic(&ellipse); ::Flatten(&line, stream); ::Flatten(&ellipse, stream); stream.Seek(0); MGraphic* graphic; ::Resurrect(graphic, stream); DisplayGraphic(graphic); delete graphic; ::Resurrect(graphic, stream); DisplayGraphic(graphic); delete graphic; //- } // This illustrates the differences between freeze levels and between flattening // and simple streaming. TContiguousGrowingStream is used as a convenience to // make it easier to access the streamed data. void TStreamingSnippets::UsingFreezeLevels() { struct { const char* name; TStream::FreezeLevel level; } levels[3] = { { "kSameTeam", TStream::kSameTeam }, { "kSameSession", TStream::kSameSession }, { "kDeepFreeze", TStream::kDeepFreeze } }; //- const TLine line(TGPoint(0, 0), TGPoint(100, 100)); const TEllipse ellipse(TGRect(10, 10, 300, 200)); TContiguousGrowingStream stream; for (int i = 0; i < 3; i++) { stream.Seek(0); stream.SetFreezeLevel(levels[i].level); ::Flatten(&line, stream); ellipse >>= stream; TMemorySurrogate buffer; stream.GetMemorySurrogate(buffer); GetDisplay() << (levels[i].name) << endl; DisplayData(buffer.GetStartAddress(), stream.GetLogicalEndOfStream()); } //- } // Use a context to ensure that networks of objects get resurrected with // their interrelationships intact. This example manually streams a small // list of pointers to shared objects, using a context to ensure that // the resurrected collection exibits the same sharing. // // The Taligent collection classes handle this for you. Additionally, Flatten // and Resurrect establish a context for the Flattened or Resurrected object // and any subobjects it may have, if no context was already in effect. So in // practice, you rarely create contexts yourself unless you're writing your // own specialized collection class or streaming a complex object // nonpolymorphically. void TStreamingSnippets::StreamUsingContext() { const TLine line(TGPoint(0, 0), TGPoint(100, 100)); const TEllipse ellipse(TGRect(10, 10, 300, 200)); const MGraphic* source[] = { &line, &ellipse, &line, &ellipse }; const int kCount = sizeof(source) / sizeof(MGraphic*); //- TGrowingChunkyStream stream(new THeapChunkyMemory()); { TStreamContextWrapper wrapper(&stream); for (int i = 0; i < kCount; i++) { ::Flatten(source[i], stream); DisplayGraphic(source[i]); } } stream.Seek(0); GetDisplay() << "------" << endl; MGraphic* result[kCount]; { TStreamContextWrapper wrapper(&stream); for (int i = 0; i < kCount; i++) { ::Resurrect(result[i], stream); DisplayGraphic(result[i]); } } //- delete result[0]; delete result[1]; } #ifndef TaligentSamples_STREAMEXAMPLE #include "StreamExample.h" #endif // This snippet uses the sample class TStreamExample (in StreamExample.h) // to illustrate version compatibility. A flag, SAMPLE_NEWVERSION, controls // which version of the class has been built into this library. Two data // files created by the generator application hold streamed representations // of the old and new version of the class. This code attempts to read in // the streamed instances from each file. If this library has been built // with SAMPLE_NEWVERSION defined, both files will be read successfully. If // not, only the first will, and an error will be thrown when the old code // attempts to read new data. void TStreamingSnippets::StreamingVersions() { #ifndef SAMPLE_NEWVERSION GetDisplay() << "SAMPLE_NEWVERSION is undefined, executing version 1 code." << endl; #else GetDisplay() << "SAMPLE_NEWVERSION is defined, executing version 2 code." << endl; #endif const char* fileNames[] = { "StreamExample.data.v1", "StreamExample.data.v2" }; const int numFiles = sizeof(fileNames)/sizeof(const char*); for (int i = 0; i < numFiles; i++) { GetDisplay() << endl << "Resurrecting from file: " << fileNames[i] << endl; try { TPathName path(TPathName::GetTaligentRoot(), "RuntimeEnv/Data/Samples"); path.Append(TPathName(fileNames[i])); TFileStream fileStream(path.GetEntity()); TStreamExample* example = NIL; while (fileStream.GetPosition() != fileStream.GetLogicalEndOfStream()) { ::Resurrect(example, fileStream); GetDisplay() << "TStreamExample instance text: " << *example->GetText() << endl; delete example; } GetDisplay() << "Resurrected all instances." << endl; } catch (const TFileSystemException&) { GetDisplay() << "Couldn't open stream on file." << endl ; } catch (const TInvalidVersionError&) { GetDisplay() << "Caught invalid version error." << endl; } } }