📄 xmpscanner.cpp
字号:
// =================================================================================================// GetSnipCount// ============longXMPScanner::GetSnipCount (){ return fInternalSnips.size();} // GetSnipCount// =================================================================================================// StreamAllScanned// ================boolXMPScanner::StreamAllScanned (){ InternalSnipIterator currPos = fInternalSnips.begin(); InternalSnipIterator endPos = fInternalSnips.end(); for ( ; currPos != endPos; ++currPos ) { if ( currPos->fInfo.fState == eNotSeenSnip ) return false; } return true;} // StreamAllScanned// =================================================================================================// SplitInternalSnip// =================//// Split the given snip into up to 3 pieces. The new pieces are inserted before and after this one// in the snip list. The relOffset is the first byte to be kept, it is relative to this snip. If// the preceeding or following snips have the same state as this one, just shift the boundaries.// I.e. move the contents from one snip to the other, don't create a new snip.// *** To be thread safe we ought to lock the entire list during manipulation. Let data scanning// *** happen in parallel, serialize all mucking with the list.voidXMPScanner::SplitInternalSnip ( InternalSnipIterator snipPos, XMP_Int64 relOffset, XMP_Int64 newLength ){ assert ( (relOffset + newLength) > relOffset ); // Check for overflow. assert ( (relOffset + newLength) <= snipPos->fInfo.fLength ); // ----------------------------------- // First deal with the low offset end. if ( relOffset > 0 ) { InternalSnipIterator prevPos; if ( snipPos != fInternalSnips.begin() ) prevPos = PrevSnip ( snipPos ); if ( (snipPos != fInternalSnips.begin()) && (snipPos->fInfo.fState == prevPos->fInfo.fState) ) { prevPos->fInfo.fLength += relOffset; // Adjust the preceeding snip. } else { InternalSnip headExcess ( snipPos->fInfo.fOffset, relOffset ); headExcess.fInfo.fState = snipPos->fInfo.fState; headExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder; fInternalSnips.insert ( snipPos, headExcess ); // Insert the head piece before the middle piece. } snipPos->fInfo.fOffset += relOffset; // Adjust the remainder of this snip. snipPos->fInfo.fLength -= relOffset; } // ---------------------------------- // Now deal with the high offset end. if ( newLength < snipPos->fInfo.fLength ) { InternalSnipIterator nextPos = NextSnip ( snipPos ); const XMP_Int64 tailLength = snipPos->fInfo.fLength - newLength; if ( (nextPos != fInternalSnips.end()) && (snipPos->fInfo.fState == nextPos->fInfo.fState) ) { nextPos->fInfo.fOffset -= tailLength; // Adjust the following snip. nextPos->fInfo.fLength += tailLength; } else { InternalSnip tailExcess ( (snipPos->fInfo.fOffset + newLength), tailLength ); tailExcess.fInfo.fState = snipPos->fInfo.fState; tailExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder; fInternalSnips.insert ( nextPos, tailExcess ); // Insert the tail piece after the middle piece. } snipPos->fInfo.fLength = newLength; }} // SplitInternalSnip// =================================================================================================// MergeInternalSnips// ==================XMPScanner::InternalSnipIteratorXMPScanner::MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos ){ firstPos->fInfo.fLength += secondPos->fInfo.fLength; fInternalSnips.erase ( secondPos ); return firstPos;} // MergeInternalSnips// =================================================================================================// Scan// ====voidXMPScanner::Scan ( const void * bufferOrigin, XMP_Int64 bufferOffset, XMP_Int64 bufferLength ){ XMP_Int64 relOffset; #if 0 cout << "Scan: @ " << bufferOrigin << ", " << bufferOffset << ", " << bufferLength << endl; #endif if ( bufferLength == 0 ) return; // ---------------------------------------------------------------- // These comparisons are carefully done to avoid overflow problems. if ( (bufferOffset >= fStreamLength) || (bufferLength > (fStreamLength - bufferOffset)) || (bufferOrigin == 0) ) { throw ScanError ( "Bad origin, offset, or length" ); } // ---------------------------------------------------------------------------------------------- // This buffer must be within a not-seen snip. Find it and split it. The first snip whose whose // end is beyond the buffer must be the enclosing one. // *** It would be friendly for rescans for out of order problems to accept any buffer postion. const XMP_Int64 endOffset = bufferOffset + bufferLength - 1; InternalSnipIterator snipPos = fInternalSnips.begin(); while ( endOffset > (snipPos->fInfo.fOffset + snipPos->fInfo.fLength - 1) ) ++ snipPos; if ( snipPos->fInfo.fState != eNotSeenSnip ) throw ScanError ( "Already seen" ); relOffset = bufferOffset - snipPos->fInfo.fOffset; if ( (relOffset + bufferLength) > snipPos->fInfo.fLength ) throw ScanError ( "Not within existing snip" ); SplitInternalSnip ( snipPos, relOffset, bufferLength ); // *** If sequential & prev is partial, just tack on, // -------------------------------------------------------- // Merge this snip with the preceeding snip if appropriate. // *** When out of order I/O is supported we have to do something about buffers who's predecessor is not seen. if ( snipPos->fInfo.fOffset > 0 ) { InternalSnipIterator prevPos = PrevSnip ( snipPos ); if ( prevPos->fInfo.fState == ePartialPacketSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos ); } // ---------------------------------- // Look for packets within this snip. snipPos->fInfo.fState = ePendingSnip; PacketMachine* thisMachine = snipPos->fMachine.get(); // DumpSnipList ( "Before scan" ); if ( thisMachine != 0 ) { thisMachine->AssociateBuffer ( bufferOffset, bufferOrigin, bufferLength ); } else { // *** snipPos->fMachine.reset ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) ); VC++ lacks reset #if 0 snipPos->fMachine = auto_ptr<PacketMachine> ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) ); #else { // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug. PacketMachine * pm = new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ); auto_ptr<PacketMachine> ap ( pm ); snipPos->fMachine = ap; } #endif thisMachine = snipPos->fMachine.get(); } bool bufferDone = false; while ( ! bufferDone ) { PacketMachine::TriState foundPacket = thisMachine->FindNextPacket(); if ( foundPacket == PacketMachine::eTriNo ) { // ----------------------------------------------------------------------- // No packet, mark the snip as raw data and get rid of the packet machine. // We're done with this buffer. snipPos->fInfo.fState = eRawInputSnip; #if 0 snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset #else { // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug. auto_ptr<PacketMachine> ap ( 0 ); snipPos->fMachine = ap; } #endif bufferDone = true; } else { // --------------------------------------------------------------------------------------------- // Either a full or partial packet. First trim any excess off of the front as a raw input snip. // If this is a partial packet mark the snip and keep the packet machine to be resumed later. // We're done with this buffer, the partial packet by definition extends to the end. If this is // a complete packet first extract the additional information from the packet machine. If there // is leftover data split the snip and transfer the packet machine to the new trailing snip. if ( thisMachine->fPacketStart > snipPos->fInfo.fOffset ) { // There is data at the front of the current snip that must be trimmed. SnipState savedState = snipPos->fInfo.fState; snipPos->fInfo.fState = eRawInputSnip; // ! So it gets propagated to the trimmed front part. relOffset = thisMachine->fPacketStart - snipPos->fInfo.fOffset; SplitInternalSnip ( snipPos, relOffset, (snipPos->fInfo.fLength - relOffset) ); snipPos->fInfo.fState = savedState; } if ( foundPacket == PacketMachine::eTriMaybe ) { // We have only found a partial packet. snipPos->fInfo.fState = ePartialPacketSnip; bufferDone = true; } else { // We have found a complete packet. Extract all the info for it and split any trailing data. InternalSnipIterator packetSnip = snipPos; SnipState packetState = eValidPacketSnip; if ( thisMachine->fBogusPacket ) packetState = eBadPacketSnip; packetSnip->fInfo.fAccess = thisMachine->fAccess; packetSnip->fInfo.fCharForm = thisMachine->fCharForm; packetSnip->fInfo.fBytesAttr = thisMachine->fBytesAttr; packetSnip->fInfo.fEncodingAttr = thisMachine->fEncodingAttr.c_str(); thisMachine->fEncodingAttr.erase ( thisMachine->fEncodingAttr.begin(), thisMachine->fEncodingAttr.end() ); if ( (thisMachine->fCharForm != eChar8Bit) && CharFormIsBigEndian ( thisMachine->fCharForm ) ) { // ------------------------------------------------------------------------------ // Handle a special case for big endian characters. The packet machine works as // though things were little endian. The packet starting offset points to the // byte containing the opening '<', and the length includes presumed nulls that // follow the last "real" byte. If the characters are big endian we now have to // decrement the starting offset of the packet, and also decrement the length of // the previous snip. // // Note that we can't do this before the head trimming above in general. The // nulls might have been exactly at the end of a buffer and already in the // previous snip. We are doing this before trimming the tail from the raw snip // containing the packet. We adjust the raw snip's size because it ends with // the input buffer. We don't adjust the packet's size, it is already correct. // // The raw snip (the one before the packet) might entirely disappear. A simple // example of this is when the packet is at the start of the file. assert ( packetSnip != fInternalSnips.begin() ); // Leading nulls were trimmed! if ( packetSnip != fInternalSnips.begin() ) { // ... but let's program defensibly. InternalSnipIterator prevSnip = PrevSnip ( packetSnip ); const unsigned int nullsToAdd = ( CharFormIs16Bit ( thisMachine->fCharForm ) ? 1 : 3 ); assert ( nullsToAdd <= prevSnip->fInfo.fLength ); prevSnip->fInfo.fLength -= nullsToAdd; if ( prevSnip->fInfo.fLength == 0 ) (void) fInternalSnips.erase ( prevSnip ); packetSnip->fInfo.fOffset -= nullsToAdd; packetSnip->fInfo.fLength += nullsToAdd; thisMachine->fPacketStart -= nullsToAdd; } } if ( thisMachine->fPacketLength == snipPos->fInfo.fLength ) { // This packet ends exactly at the end of the current snip. #if 0 snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset #else { // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug. auto_ptr<PacketMachine> ap ( 0 ); snipPos->fMachine = ap; } #endif bufferDone = true; } else { // There is trailing data to split from the just found packet. SplitInternalSnip ( snipPos, 0, thisMachine->fPacketLength ); InternalSnipIterator tailPos = NextSnip ( snipPos ); tailPos->fMachine = snipPos->fMachine; // auto_ptr assignment - taking ownership thisMachine->ResetMachine (); snipPos = tailPos; } packetSnip->fInfo.fState = packetState; // Do this last to avoid messing up the tail split. // DumpSnipList ( "Found a packet" ); } } } // -------------------------------------------------------- // Merge this snip with the preceeding snip if appropriate. // *** When out of order I/O is supported we have to check the following snip too. if ( (snipPos->fInfo.fOffset > 0) && (snipPos->fInfo.fState == eRawInputSnip) ) { InternalSnipIterator prevPos = PrevSnip ( snipPos ); if ( prevPos->fInfo.fState == eRawInputSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos ); } // DumpSnipList ( "After scan" ); } // Scan// =================================================================================================// Report// ======voidXMPScanner::Report ( SnipInfoVector& snips ){ const int count = fInternalSnips.size(); InternalSnipIterator snipPos = fInternalSnips.begin(); int s; // DumpSnipList ( "Report" ); snips.erase ( snips.begin(), snips.end() ); // ! Should use snips.clear, but VC++ doesn't have it. snips.reserve ( count ); for ( s = 0; s < count; s += 1 ) { snips.push_back ( SnipInfo ( snipPos->fInfo.fState, snipPos->fInfo.fOffset, snipPos->fInfo.fLength ) ); snips[s] = snipPos->fInfo; // Pick up all of the fields. ++ snipPos; }} // Report
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -