auto readTransaction () { const auto source = this->data; const auto version = this->data.read<int32_t>(); const auto nInputs = readVI(this->data); std::vector<Transaction::Input> inputs; for (size_t i = 0; i < nInputs; ++i) { const auto idataSource = this->data; const auto hash = readSlice(this->data, 32); const auto vout = this->data.read<uint32_t>(); const auto scriptLen = readVI(this->data); const auto script = readSlice(this->data, scriptLen); const auto sequence = this->data.read<uint32_t>(); const auto idata = Slice(idataSource.begin, this->data.begin); inputs.emplace_back( Transaction::Input(idata, hash, vout, script, sequence) ); } const auto nOutputs = readVI(this->data); std::vector<Transaction::Output> outputs; for (size_t i = 0; i < nOutputs; ++i) { const auto odataSource = this->data; const auto value = this->data.read<uint64_t>(); const auto scriptLen = readVI(this->data); const auto script = readSlice(this->data, scriptLen); const auto odata = Slice(odataSource.begin, this->data.begin); outputs.emplace_back(Transaction::Output(odata, script, value)); } const auto locktime = this->data.read<uint32_t>(); const auto _data = source.take(source.length() - this->data.length()); this->current = Transaction(_data, version, std::move(inputs), std::move(outputs), locktime); this->lazy = false; }
AINLINE void SelectBufferedSlice( bufferAbstractType *buffer, CBufferedStreamWrap::bufferSeekPointer_t& bufOffset, seekGenericType& fileSeek, size_t requestedReadCount, callbackType& cb ) { typedef CBufferedStreamWrap::seekSlice_t seekSlice_t; typedef CBufferedStreamWrap::seekType_t seekType_t; // If we do not want to read anything, quit right away. if ( requestedReadCount == 0 ) return; #ifdef FILESYSTEM_PERFORM_SANITY_CHECKS // Add simple error checking. // It could be fatal to the application to introduce an infinite loop here. unsigned int methodRepeatCount = 0; #endif //FILESYSTEM_PERFORM_SANITY_CHECKS repeatMethod: #if FILESYSTEM_PERFORM_SANITY_CHECKS methodRepeatCount++; if ( methodRepeatCount == 6000000 ) throw std::exception( "infinite buffered select repetition count" ); #endif //FILESYSTEM_PERFORM_SANITY_CHECKS // Do the actual logic. seekType_t localFileSeek = fileSeek.Tell(); size_t bufferSize = cb.GetBufferSize(); // Create the slices for the seeking operation. // We will collide them against each other. seekSlice_t readSlice( localFileSeek, requestedReadCount ); seekSlice_t bufferSlice( bufOffset.offsetOfBufferOnFileSpace, bufferSize ); seekSlice_t::eIntersectionResult intResult = readSlice.intersectWith( bufferSlice ); // Make sure the content is prepared for the action. bool hasToRepeat = cb.ContentInvokation( buffer, localFileSeek, requestedReadCount, intResult ); if ( hasToRepeat ) goto repeatMethod; if ( intResult == seekSlice_t::INTERSECT_EQUAL ) { cb.BufferedInvokation( buffer, 0, requestedReadCount ); fileSeek.Seek( localFileSeek + requestedReadCount ); } else if ( intResult == seekSlice_t::INTERSECT_INSIDE ) { cb.BufferedInvokation( buffer, (size_t)( localFileSeek - bufOffset.offsetOfBufferOnFileSpace ), requestedReadCount ); fileSeek.Seek( localFileSeek + requestedReadCount ); } else if ( intResult == seekSlice_t::INTERSECT_BORDER_END ) { // Everything read-able has to fit inside client memory. // A size_t is assumed to be as big as the client memory allows. size_t sliceStartOffset = (size_t)( bufferSlice.GetSliceStartPoint() - localFileSeek ); // First read from the file natively, to reach the buffer border. if ( sliceStartOffset > 0 ) { // Make sure the seek pointer is up to date. fileSeek.Update(); size_t actualReadCount = 0; cb.NativeInvokation( buffer, sliceStartOffset, actualReadCount ); // Update the file seek. fileSeek.Seek( localFileSeek += actualReadCount ); // Predict that we advanced by some bytes. fileSeek.PredictNativeAdvance( (seekType_t)actualReadCount ); } // Now lets read the remainder from the buffer. size_t sliceReadRemainderCount = (size_t)( requestedReadCount - sliceStartOffset ); if ( sliceReadRemainderCount > 0 ) { cb.BufferedInvokation( buffer + sliceStartOffset, 0, sliceReadRemainderCount ); fileSeek.Seek( localFileSeek += sliceReadRemainderCount ); } } else if ( intResult == seekSlice_t::INTERSECT_BORDER_START ) { // The_GTA: That +1 is very complicated. Just roll with it! size_t sliceEndOffset = (size_t)( bufferSlice.GetSliceEndPoint() + 1 - localFileSeek ); // Read what can be read from the native buffer. if ( sliceEndOffset > 0 ) { size_t sliceReadInCount = (size_t)( bufferSize - sliceEndOffset ); cb.BufferedInvokation( buffer, sliceReadInCount, sliceEndOffset ); // Update the local file seek. fileSeek.Seek( localFileSeek += sliceEndOffset ); } // Increment the buffer location and read the requested content into it. size_t sliceReadRemainderCount = (size_t)( requestedReadCount - sliceEndOffset ); if ( sliceReadRemainderCount > 0 ) { // Update the perform details. buffer += sliceEndOffset; requestedReadCount = sliceReadRemainderCount; goto repeatMethod; } } else if ( intResult == seekSlice_t::INTERSECT_ENCLOSING ) { // Read the beginning segment, that is native file memory. size_t sliceStartOffset = (size_t)( bufferSlice.GetSliceStartPoint() - localFileSeek ); if ( sliceStartOffset > 0 ) { // Make sure the seek pointer is up-to-date. fileSeek.Update(); size_t actualReadCount = 0; cb.NativeInvokation( buffer, sliceStartOffset, actualReadCount ); // Update the seek ptr. fileSeek.Seek( localFileSeek += sliceStartOffset ); // Predict that the real file offset advanced by some bytes. fileSeek.PredictNativeAdvance( (seekType_t)actualReadCount ); } // Put the content of the entire internal buffer into the output buffer. { cb.BufferedInvokation( buffer + sliceStartOffset, 0, bufferSize ); fileSeek.Seek( localFileSeek += bufferSize ); } // Read the part after the internal buffer slice. // This part must be executed on the buffer context. size_t sliceEndOffset = (size_t)( readSlice.GetSliceEndPoint() - bufferSlice.GetSliceEndPoint() ); if ( sliceEndOffset > 0 ) { // Update execution parameters and continue to dispatch. buffer += sliceStartOffset + bufferSize; requestedReadCount = sliceEndOffset; goto repeatMethod; } } else if ( seekSlice_t::isFloatingIntersect( intResult ) || intResult == seekSlice_t::INTERSECT_UNKNOWN ) { // Notify the callback about out-of-bounds content access. bool shouldContinue = cb.FloatingInvokation( buffer, localFileSeek, requestedReadCount, intResult ); if ( shouldContinue ) { // Update buffer contents depending on the stream position. UpdateStreamedBufferPosition( bufOffset, fileSeek, cb ); // Attempt to repeat reading. goto repeatMethod; } } else { // We have no hit in any way that we can detect. // Throw an exception. assert( 0 ); } }