Esempio n. 1
0
	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 );
    }
}