/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkXMLDataParser.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkXMLDataParser.h" #include "vtkBase64InputStream.h" #include "vtkByteSwap.h" #include "vtkCommand.h" #include "vtkDataCompressor.h" #include "vtkInputStream.h" #include "vtkObjectFactory.h" #include "vtkXMLDataElement.h" vtkCxxRevisionMacro(vtkXMLDataParser, "$Revision: 1.29.6.1 $"); vtkStandardNewMacro(vtkXMLDataParser); vtkCxxSetObjectMacro(vtkXMLDataParser, Compressor, vtkDataCompressor); //---------------------------------------------------------------------------- vtkXMLDataParser::vtkXMLDataParser() { this->NumberOfOpenElements = 0; this->OpenElementsSize = 10; this->OpenElements = new vtkXMLDataElement*[this->OpenElementsSize]; this->RootElement = 0; this->AppendedDataPosition = 0; this->AppendedDataMatched = 0; this->DataStream = 0; this->InlineDataStream = vtkBase64InputStream::New(); this->AppendedDataStream = vtkBase64InputStream::New(); this->BlockCompressedSizes = 0; this->BlockStartOffsets = 0; this->Compressor = 0; this->AsciiDataBuffer = 0; this->AsciiDataBufferLength = 0; this->AsciiDataPosition = 0; this->Abort = 0; this->Progress = 0; // Default byte order to that of this machine. #ifdef VTK_WORDS_BIGENDIAN this->ByteOrder = vtkXMLDataParser::BigEndian; #else this->ByteOrder = vtkXMLDataParser::LittleEndian; #endif this->AttributesEncoding = VTK_ENCODING_NONE; } //---------------------------------------------------------------------------- vtkXMLDataParser::~vtkXMLDataParser() { this->FreeAllElements(); delete [] this->OpenElements; this->InlineDataStream->Delete(); this->AppendedDataStream->Delete(); if(this->BlockCompressedSizes) { delete [] this->BlockCompressedSizes; } if(this->BlockStartOffsets) { delete [] this->BlockStartOffsets; } this->SetCompressor(0); if(this->AsciiDataBuffer) { this->FreeAsciiBuffer(); } } //---------------------------------------------------------------------------- void vtkXMLDataParser::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "AppendedDataPosition: " << this->AppendedDataPosition << "\n"; if(this->RootElement) { this->RootElement->PrintXML(os, indent); } if(this->Compressor) { os << indent << "Compressor: " << this->Compressor << "\n"; } else { os << indent << "Compressor: (none)\n"; } os << indent << "Progress: " << this->Progress << "\n"; os << indent << "Abort: " << this->Abort << "\n"; os << indent << "AttributesEncoding: " << this->AttributesEncoding << "\n"; } //---------------------------------------------------------------------------- int vtkXMLDataParser::Parse() { // Delete any elements left from previous parsing. this->FreeAllElements(); // Parse the input from the stream. int result = this->Superclass::Parse(); // Check that the input is okay. if(result && !this->CheckPrimaryAttributes()) { result = 0; } return result; } //---------------------------------------------------------------------------- int vtkXMLDataParser::Parse(const char*) { vtkErrorMacro("Parsing from a string is not supported."); return 0; } //---------------------------------------------------------------------------- int vtkXMLDataParser::Parse(const char*, unsigned int) { vtkErrorMacro("Parsing from a string is not supported."); return 0; } //---------------------------------------------------------------------------- void vtkXMLDataParser::StartElement(const char* name, const char** atts) { vtkXMLDataElement* element = vtkXMLDataElement::New(); element->SetName(name); element->SetXMLByteIndex(this->GetXMLByteIndex()); element->ReadXMLAttributes(atts, this->AttributesEncoding); const char* id = element->GetAttribute("id"); if(id) { element->SetId(id); } this->PushOpenElement(element); if(strcmp(name, "AppendedData") == 0) { // This is the AppendedData element. this->FindAppendedDataPosition(); // Switch to raw decoder if necessary. const char* encoding = element->GetAttribute("encoding"); if(encoding && (strcmp(encoding, "raw") == 0)) { this->AppendedDataStream->Delete(); this->AppendedDataStream = vtkInputStream::New(); } } } //---------------------------------------------------------------------------- void vtkXMLDataParser::EndElement(const char*) { vtkXMLDataElement* finished = this->PopOpenElement(); unsigned int numOpen = this->NumberOfOpenElements; if(numOpen > 0) { this->OpenElements[numOpen-1]->AddNestedElement(finished); finished->Delete(); } else { this->RootElement = finished; } } //---------------------------------------------------------------------------- int vtkXMLDataParser::ParsingComplete() { // If we have reached the appended data section, we stop parsing. // This prevents the XML parser from having to walk over the entire // appended data section. if(this->AppendedDataPosition) { return 1; } return this->Superclass::ParsingComplete(); } //---------------------------------------------------------------------------- int vtkXMLDataParser::CheckPrimaryAttributes() { const char* byte_order = this->RootElement->GetAttribute("byte_order"); if(byte_order) { if(strcmp(byte_order, "BigEndian") == 0) { this->ByteOrder = vtkXMLDataParser::BigEndian; } else if(strcmp(byte_order, "LittleEndian") == 0) { this->ByteOrder = vtkXMLDataParser::LittleEndian; } else { vtkErrorMacro("Unsupported byte_order=\"" << byte_order << "\""); return 0; } } return 1; } //---------------------------------------------------------------------------- void vtkXMLDataParser::FindAppendedDataPosition() { // Clear stream fail and eof bits. We may have already read past // the end of the stream when processing the AppendedData element. this->Stream->clear(this->Stream->rdstate() & ~ios::failbit); this->Stream->clear(this->Stream->rdstate() & ~ios::eofbit); // Scan for the start of the actual appended data. char c=0; long returnPosition = this->TellG(); this->SeekG(this->GetXMLByteIndex()); while(this->Stream->get(c) && (c != '>')); while(this->Stream->get(c) && this->IsSpace(c)); // Store the start of the appended data. We skip the first // character because it is always a "_". this->AppendedDataPosition = this->TellG(); // If first character was not an underscore, assume it is part of // the data. if(c != '_') { vtkWarningMacro("First character in AppendedData is ASCII value " << int(c) << ", not '_'. Scan for first character " << "started from file position " << this->GetXMLByteIndex() << ". The return position is " << returnPosition << "."); --this->AppendedDataPosition; } // Restore the stream position. this->SeekG(returnPosition); } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::FindInlineDataPosition(OffsetType start) { // Scan for the start of the actual inline data. char c=0; this->SeekG(start); while(this->Stream->get(c) && (c != '>')); while(this->Stream->get(c) && this->IsSpace(c)); // Make sure some data were found. if(c == '<') { return 0; } OffsetType pos = this->TellG(); return (pos-1); } //---------------------------------------------------------------------------- void vtkXMLDataParser::PushOpenElement(vtkXMLDataElement* element) { if(this->NumberOfOpenElements == this->OpenElementsSize) { unsigned int newSize = this->OpenElementsSize*2; vtkXMLDataElement** newOpenElements = new vtkXMLDataElement*[newSize]; unsigned int i; for(i=0; i < this->NumberOfOpenElements;++i) { newOpenElements[i] = this->OpenElements[i]; } delete [] this->OpenElements; this->OpenElements = newOpenElements; this->OpenElementsSize = newSize; } unsigned int pos = this->NumberOfOpenElements++; this->OpenElements[pos] = element; } //---------------------------------------------------------------------------- vtkXMLDataElement* vtkXMLDataParser::PopOpenElement() { if(this->NumberOfOpenElements > 0) { --this->NumberOfOpenElements; return this->OpenElements[this->NumberOfOpenElements]; } return 0; } //---------------------------------------------------------------------------- void vtkXMLDataParser::FreeAllElements() { while(this->NumberOfOpenElements > 0) { --this->NumberOfOpenElements; this->OpenElements[this->NumberOfOpenElements]->Delete(); this->OpenElements[this->NumberOfOpenElements] = 0; } if(this->RootElement) { this->RootElement->Delete(); this->RootElement = 0; } } //---------------------------------------------------------------------------- int vtkXMLDataParser::ParseBuffer(const char* buffer, unsigned int count) { // Parsing must stop when "AppendedDataMatched; while(s != end) { char c = *s++; if(c == pattern[matched]) { if(++matched == length) { break; } } else { matched = (c == pattern[0])? 1:0; } } this->AppendedDataMatched = matched; // Parse as much of the buffer as is safe. if(!this->Superclass::ParseBuffer(buffer, s - buffer)) { return 0; } // If we have reached the appended data, artificially finish the // document. if(matched == length) { // Parse the rest of the element's opening tag. const char* t = s; char prev = 0; while((t != end) && (*t != '>')) { ++t; } if(!this->Superclass::ParseBuffer(s, t-s)) { return 0; } if(t > s) { prev = *(t-1); } if(t == end) { // Scan for the real end of the element's opening tag. char c=0; while(this->Stream->get(c) && (c != '>')) { prev = c; if(!this->Superclass::ParseBuffer(&c, 1)) { return 0; } } } // Artificially end the AppendedData element. if(prev != '/') { if(!this->Superclass::ParseBuffer("/", 1)) { return 0; } } if(!this->Superclass::ParseBuffer(">", 1)) { return 0; } // Artificially end the VTKFile element. const char finish[] = "\n\n"; if(!this->Superclass::ParseBuffer(finish, sizeof(finish)-1)) { return 0; } } return 1; } //---------------------------------------------------------------------------- template unsigned long vtkXMLDataParserGetWordTypeSize(T*) { return sizeof(T); } //---------------------------------------------------------------------------- unsigned long vtkXMLDataParser::GetWordTypeSize(int wordType) { unsigned long size = 1; switch (wordType) { vtkTemplateMacro( size = vtkXMLDataParserGetWordTypeSize(static_cast(0)) ); default: { vtkWarningMacro("Unsupported data type: " << wordType); } break; } return size; } //---------------------------------------------------------------------------- void vtkXMLDataParser::PerformByteSwap(void* data, OffsetType numWords, int wordSize) { char* ptr = static_cast(data); if(this->ByteOrder == vtkXMLDataParser::BigEndian) { switch (wordSize) { case 1: break; case 2: vtkByteSwap::Swap2BERange(ptr, numWords); break; case 4: vtkByteSwap::Swap4BERange(ptr, numWords); break; case 8: vtkByteSwap::Swap8BERange(ptr, numWords); break; default: vtkErrorMacro("Unsupported data type size " << wordSize); } } else { switch (wordSize) { case 1: break; case 2: vtkByteSwap::Swap2LERange(ptr, numWords); break; case 4: vtkByteSwap::Swap4LERange(ptr, numWords); break; case 8: vtkByteSwap::Swap8LERange(ptr, numWords); break; default: vtkErrorMacro("Unsupported data type size " << wordSize); } } } //---------------------------------------------------------------------------- void vtkXMLDataParser::ReadCompressionHeader() { HeaderType headerBuffer[3]; const int headerSize = sizeof(headerBuffer); unsigned char* buffer = reinterpret_cast(&headerBuffer[0]); this->DataStream->StartReading(); // Read the standard part of the header. int r = this->DataStream->Read(buffer, headerSize); if(r < headerSize) { vtkErrorMacro("Error reading beginning of compression header. Read " << r << " of " << headerSize << " bytes."); return; } // Byte swap the header to make sure the values are correct. this->PerformByteSwap(headerBuffer, 3, sizeof(HeaderType)); // Get the standard values. this->NumberOfBlocks = headerBuffer[0]; this->BlockUncompressedSize = headerBuffer[1]; this->PartialLastBlockUncompressedSize = headerBuffer[2]; // Allocate the size and offset parts of the header. if(this->BlockCompressedSizes) { delete [] this->BlockCompressedSizes; this->BlockCompressedSizes = 0; } if(this->BlockStartOffsets) { delete [] this->BlockStartOffsets; this->BlockStartOffsets = 0; } if(this->NumberOfBlocks > 0) { this->BlockCompressedSizes = new HeaderType[this->NumberOfBlocks]; this->BlockStartOffsets = new OffsetType[this->NumberOfBlocks]; buffer = reinterpret_cast(&this->BlockCompressedSizes[0]); // Read the compressed block sizes. unsigned long len = this->NumberOfBlocks*sizeof(HeaderType); if(this->DataStream->Read(buffer, len) < len) { vtkErrorMacro("Error reading compression header."); return; } // Byte swap the sizes to make sure the values are correct. this->PerformByteSwap(buffer, this->NumberOfBlocks, sizeof(HeaderType)); } this->DataStream->EndReading(); // Use the compressed block sizes to calculate the starting offset // of each block. OffsetType offset = 0; unsigned int i; for(i=0;i < this->NumberOfBlocks;++i) { this->BlockStartOffsets[i] = offset; offset += this->BlockCompressedSizes[i]; } } //---------------------------------------------------------------------------- unsigned int vtkXMLDataParser::FindBlockSize(unsigned int block) { if(block < this->NumberOfBlocks-(this->PartialLastBlockUncompressedSize?1:0)) { return this->BlockUncompressedSize; } else { return this->PartialLastBlockUncompressedSize; } } //---------------------------------------------------------------------------- int vtkXMLDataParser::ReadBlock(unsigned int block, unsigned char* buffer) { OffsetType uncompressedSize = this->FindBlockSize(block); unsigned int compressedSize = this->BlockCompressedSizes[block]; unsigned char* readBuffer = new unsigned char[compressedSize]; if(!this->DataStream->Seek(this->BlockStartOffsets[block])) { return 0; } if(this->DataStream->Read(readBuffer, compressedSize) < compressedSize) { return 0; } OffsetType result = this->Compressor->Uncompress(readBuffer, compressedSize, buffer, uncompressedSize); delete [] readBuffer; return (result > 0)? 1:0; } //---------------------------------------------------------------------------- unsigned char* vtkXMLDataParser::ReadBlock(unsigned int block) { unsigned char* decompressBuffer = new unsigned char[this->FindBlockSize(block)]; if(!this->ReadBlock(block, decompressBuffer)) { delete [] decompressBuffer; return 0; } return decompressBuffer; } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::ReadUncompressedData(unsigned char* data, OffsetType startWord, OffsetType numWords, int wordSize) { // First read the length of the data. HeaderType rsize; const unsigned long len = sizeof(HeaderType); unsigned char* p = reinterpret_cast(&rsize); if(this->DataStream->Read(p, len) < len) { return 0; } this->PerformByteSwap(&rsize, 1, len); // Adjust the size to be a multiple of the wordSize by taking // advantage of integer division. This will only change the value // when the input file is invalid. OffsetType size = (rsize/wordSize)*wordSize; // Convert the start/length into bytes. OffsetType offset = startWord*wordSize; OffsetType length = numWords*wordSize; // Make sure the begin/end offsets fall within total size. if(offset > size) { return 0; } OffsetType end = offset+length; if(end > size) { end = size; } length = end-offset; // Read the data. if(!this->DataStream->Seek(offset+len)) { return 0; } // Read data in 32KB blocks and report progress. const long blockSize = 32768; long left = length; p = data; this->UpdateProgress(0); while(left > 0 && !this->Abort) { // Read this block. long n = (blockSize < left)? blockSize:left; if(!this->DataStream->Read(p, n)) { return 0; } // Byte swap this block. Note that n will always be an integer // multiple of the word size. this->PerformByteSwap(p, n / wordSize, wordSize); // Update pointer and counter. p += n; left -= n; // Report progress. this->UpdateProgress(float(p-data)/length); } this->UpdateProgress(1); return length/wordSize; } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::ReadCompressedData(unsigned char* data, OffsetType startWord, OffsetType numWords, int wordSize) { // Make sure there are data. if(numWords == 0) { return 0; } // Find the begin and end offsets into the data. OffsetType beginOffset = startWord*wordSize; OffsetType endOffset = beginOffset+numWords*wordSize; // Find the total size of the data. OffsetType totalSize = this->NumberOfBlocks*this->BlockUncompressedSize; if(this->PartialLastBlockUncompressedSize) { totalSize -= this->BlockUncompressedSize; totalSize += this->PartialLastBlockUncompressedSize; } // Adjust the size to be a multiple of the wordSize by taking // advantage of integer division. This will only change the value // when the input file is invalid. totalSize = (totalSize/wordSize)*wordSize; // Make sure the begin/end offsets fall within the total size. if(beginOffset > totalSize) { return 0; } if(endOffset > totalSize) { endOffset = totalSize; } // Find the range of compression blocks to read. unsigned int firstBlock = beginOffset / this->BlockUncompressedSize; unsigned int lastBlock = endOffset / this->BlockUncompressedSize; // Find the offset into the first block where the data begin. unsigned int beginBlockOffset = beginOffset - firstBlock*this->BlockUncompressedSize; // Find the offset into the last block where the data end. unsigned int endBlockOffset = endOffset - lastBlock*this->BlockUncompressedSize; this->UpdateProgress(0); if(firstBlock == lastBlock) { // Everything fits in one block. unsigned char* blockBuffer = this->ReadBlock(firstBlock); if(!blockBuffer) { return 0; } long n = endBlockOffset - beginBlockOffset; memcpy(data, blockBuffer+beginBlockOffset, n); delete [] blockBuffer; // Byte swap this block. Note that n will always be an integer // multiple of the word size. this->PerformByteSwap(data, n / wordSize, wordSize); } else { // Read all the complete blocks first. OffsetType length = endOffset - beginOffset; unsigned char* outputPointer = data; OffsetType blockSize = this->FindBlockSize(firstBlock); // Read the first block. unsigned char* blockBuffer = this->ReadBlock(firstBlock); if(!blockBuffer) { return 0; } long n = blockSize-beginBlockOffset; memcpy(outputPointer, blockBuffer+beginBlockOffset, n); delete [] blockBuffer; // Byte swap the first block. Note that n will always be an // integer multiple of the word size. this->PerformByteSwap(outputPointer, n / wordSize, wordSize); // Advance the pointer to the beginning of the second block. outputPointer += blockSize-beginBlockOffset; // Report progress. this->UpdateProgress(float(outputPointer-data)/length); unsigned int currentBlock = firstBlock+1; for(;currentBlock != lastBlock && !this->Abort; ++currentBlock) { // Read this block. if(!this->ReadBlock(currentBlock, outputPointer)) { return 0; } // Byte swap this block. Note that blockSize will always be an // integer multiple of the word size. this->PerformByteSwap(outputPointer, blockSize / wordSize, wordSize); // Advance the pointer to the beginning of the next block. outputPointer += this->FindBlockSize(currentBlock); // Report progress. this->UpdateProgress(float(outputPointer-data)/length); } // Now read the final block, which is incomplete if it exists. if(endBlockOffset > 0 && !this->Abort) { blockBuffer = this->ReadBlock(lastBlock); if(!blockBuffer) { return 0; } memcpy(outputPointer, blockBuffer, endBlockOffset); delete [] blockBuffer; // Byte swap the partial block. Note that endBlockOffset will // always be an integer multiple of the word size. this->PerformByteSwap(outputPointer, endBlockOffset / wordSize, wordSize); } } this->UpdateProgress(1); // Return the total words actually read. return (endOffset - beginOffset)/wordSize; } //---------------------------------------------------------------------------- vtkXMLDataElement* vtkXMLDataParser::GetRootElement() { return this->RootElement; } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::ReadBinaryData(void* in_buffer, OffsetType startWord, OffsetType numWords, int wordType) { // Skip real read if aborting. if(this->Abort) { return 0; } unsigned long wordSize = this->GetWordTypeSize(wordType); void* buffer = in_buffer; // Make sure our streams are setup correctly. this->DataStream->SetStream(this->Stream); // Read the data. unsigned char* d = reinterpret_cast(buffer); OffsetType actualWords; if(this->Compressor) { this->ReadCompressionHeader(); this->DataStream->StartReading(); actualWords = this->ReadCompressedData(d, startWord, numWords, wordSize); this->DataStream->EndReading(); } else { this->DataStream->StartReading(); actualWords = this->ReadUncompressedData(d, startWord, numWords, wordSize); this->DataStream->EndReading(); } // Return the actual amount read. return this->Abort? 0:actualWords; } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::ReadAsciiData(void* buffer, OffsetType startWord, OffsetType numWords, int wordType) { // Skip real read if aborting. if(this->Abort) { return 0; } // We assume that ascii data are not very large and parse the entire // block into memory. this->UpdateProgress(0); // Parse the ascii data from the file. if(!this->ParseAsciiData(wordType)) { return 0; } // Make sure we don't read outside the range of data available. OffsetType endWord = startWord + numWords; if(this->AsciiDataBufferLength < startWord) { return 0; } if(endWord > this->AsciiDataBufferLength) { endWord = this->AsciiDataBufferLength; } unsigned long wordSize = this->GetWordTypeSize(wordType); OffsetType actualWords = endWord - startWord; OffsetType actualBytes = wordSize*actualWords; OffsetType startByte = wordSize*startWord; this->UpdateProgress(0.5); // Copy the data from the pre-parsed ascii data buffer. memcpy(buffer, this->AsciiDataBuffer+startByte, actualBytes); this->UpdateProgress(1); return this->Abort? 0:actualWords; } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::ReadInlineData(vtkXMLDataElement* element, int isAscii, void* buffer, OffsetType startWord, OffsetType numWords, int wordType) { this->DataStream = this->InlineDataStream; element->SeekInlineDataPosition(this); if(isAscii) { return this->ReadAsciiData(buffer, startWord, numWords, wordType); } else { return this->ReadBinaryData(buffer, startWord, numWords, wordType); } } //---------------------------------------------------------------------------- vtkXMLDataParser::OffsetType vtkXMLDataParser::ReadAppendedData(OffsetType offset, void* buffer, OffsetType startWord, OffsetType numWords, int wordType) { this->DataStream = this->AppendedDataStream; this->SeekG(this->AppendedDataPosition+offset); return this->ReadBinaryData(buffer, startWord, numWords, wordType); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // Define a parsing function template. The extra "long" argument is used // to help broken compilers select the non-templates below for char and // unsigned char by making them a better conversion than the template. template T* vtkXMLParseAsciiData(istream& is, int* length, T*, long) { int dataLength = 0; int dataBufferSize = 64; T* dataBuffer = new T[dataBufferSize]; T element; while(is >> element) { if(dataLength == dataBufferSize) { int newSize = dataBufferSize*2; T* newBuffer = new T[newSize]; memcpy(newBuffer, dataBuffer, dataLength*sizeof(T)); delete [] dataBuffer; dataBuffer = newBuffer; dataBufferSize = newSize; } dataBuffer[dataLength++] = element; } if(length) { *length = dataLength; } return dataBuffer; } //---------------------------------------------------------------------------- char* vtkXMLParseAsciiData(istream& is, int* length, char*, int) { int dataLength = 0; int dataBufferSize = 64; char* dataBuffer = new char[dataBufferSize]; char element; short inElement; while(is >> inElement) { element = inElement; if(dataLength == dataBufferSize) { int newSize = dataBufferSize*2; char* newBuffer = new char[newSize]; memcpy(newBuffer, dataBuffer, dataLength*sizeof(char)); delete [] dataBuffer; dataBuffer = newBuffer; dataBufferSize = newSize; } dataBuffer[dataLength++] = element; } if(length) { *length = dataLength; } return dataBuffer; } //---------------------------------------------------------------------------- unsigned char* vtkXMLParseAsciiData(istream& is, int* length, unsigned char*, int) { int dataLength = 0; int dataBufferSize = 64; unsigned char* dataBuffer = new unsigned char[dataBufferSize]; unsigned char element; short inElement; while(is >> inElement) { element = inElement; if(dataLength == dataBufferSize) { int newSize = dataBufferSize*2; unsigned char* newBuffer = new unsigned char[newSize]; memcpy(newBuffer, dataBuffer, dataLength*sizeof(unsigned char)); delete [] dataBuffer; dataBuffer = newBuffer; dataBufferSize = newSize; } dataBuffer[dataLength++] = element; } if(length) { *length = dataLength; } return dataBuffer; } //---------------------------------------------------------------------------- signed char* vtkXMLParseAsciiData(istream& is, int* length, signed char*, int) { int dataLength = 0; int dataBufferSize = 64; signed char* dataBuffer = new signed char[dataBufferSize]; signed char element; short inElement; while(is >> inElement) { element = inElement; if(dataLength == dataBufferSize) { int newSize = dataBufferSize*2; signed char* newBuffer = new signed char[newSize]; memcpy(newBuffer, dataBuffer, dataLength*sizeof(signed char)); delete [] dataBuffer; dataBuffer = newBuffer; dataBufferSize = newSize; } dataBuffer[dataLength++] = element; } if(length) { *length = dataLength; } return dataBuffer; } //---------------------------------------------------------------------------- int vtkXMLDataParser::ParseAsciiData(int wordType) { istream& is = *(this->Stream); // Don't re-parse the same ascii data. if(this->AsciiDataPosition == static_cast(this->TellG())) { return (this->AsciiDataBuffer? 1:0); } // Prepare for new data. this->AsciiDataPosition = this->TellG(); if(this->AsciiDataBuffer) { this->FreeAsciiBuffer(); } int length = 0; void* buffer = 0; switch (wordType) { vtkTemplateMacro( buffer = vtkXMLParseAsciiData(is, &length, static_cast(0), 1) ); } // Read terminated from failure. Clear the fail bit so another read // can take place later. is.clear(is.rdstate() & ~ios::failbit); // Save the buffer. this->AsciiDataBuffer = reinterpret_cast(buffer); this->AsciiDataBufferLength = length; this->AsciiDataWordType = wordType; return (this->AsciiDataBuffer? 1:0); } //---------------------------------------------------------------------------- template void vtkXMLDataParserFreeAsciiBuffer(T* buffer) { delete [] buffer; } //---------------------------------------------------------------------------- void vtkXMLDataParser::FreeAsciiBuffer() { void* buffer = this->AsciiDataBuffer; switch (this->AsciiDataWordType) { vtkTemplateMacro( vtkXMLDataParserFreeAsciiBuffer(static_cast(buffer)) ); } this->AsciiDataBuffer = 0; } //---------------------------------------------------------------------------- void vtkXMLDataParser::UpdateProgress(float progress) { this->Progress = progress; this->InvokeEvent(vtkCommand::ProgressEvent, &progress); }