Пример #1
0
        internal int WriteLengthPrefixed <TValue>(TValue value, uint underEstimatedLength, ILengthProperty <TValue> property)
        {
            Flush(); // commit to the stream before monkeying with the buffers...

            MemoryStream ms = stream as MemoryStream;

            if (ms != null)
            {
                // we'll write to out current stream, optimising
                // for the case when the length-prefix is 1-byte;
                // if not we'll have to BlockCopy
                int  startIndex        = (int)ms.Position;
                uint guessLength       = underEstimatedLength,
                     guessPrefixLength = (uint)this.EncodeUInt32(guessLength),
                     actualLength      = (uint)property.Serialize(value, this);

                if (guessLength == actualLength)
                { // good guess! nothing to do...
                    return((int)(guessPrefixLength + actualLength));
                }

                uint actualPrefixLength = (uint)SerializationContext.GetLength(actualLength);

                Flush(); // commit to the stream before we start messing with it...

                if (actualPrefixLength < guessPrefixLength)
                {
                    throw new ProtoException("Internal error; the serializer over-estimated the length. Sorry, but this shouldn't have happened.");
                }
                else if (actualPrefixLength > guessPrefixLength)
                {
                    // our guess of the length turned out to be bad; we need to
                    // fix things...

                    // extend the buffer to ensure we have space
                    for (uint i = actualPrefixLength - guessPrefixLength; i > 0; i--)
                    {
                        ms.WriteByte(0);
                        position++;
                    }

                    // move the data
                    // (note; we MUST call GetBuffer *after* extending it,
                    // otherwise there the buffer might change if we extend
                    // over a boundary)
                    byte[] buffer = ms.GetBuffer();
                    Buffer.BlockCopy(buffer, (int)(startIndex + guessPrefixLength),
                                     buffer, (int)(startIndex + actualPrefixLength), (int)actualLength);
                }

                // back-fill the actual length into the buffer
                SerializationContext.EncodeUInt32(actualLength, ms.GetBuffer(), startIndex);
                return((int)(actualPrefixLength + actualLength));
            }
            else
            {
                // create a temporary stream and write the final result
                using (ms = new MemoryStream())
                {
                    SerializationContext ctx = new SerializationContext(ms, this);
                    int len = property.Serialize(value, ctx);
                    ctx.Flush();
                    this.ReadFrom(ctx);

                    int    preambleLen = this.EncodeInt32(len);
                    byte[] buffer      = ms.GetBuffer();
                    this.WriteBlock(buffer, 0, len);
                    return(preambleLen + len);
                }
            }
        }