Example #1
0
        private static void EndSubItem(SubItemToken token, ProtoWriter writer, PrefixStyle style)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (writer.wireType != WireType.None)
            {
                throw CreateException(writer);
            }
            int value = (int)token.value64;

            if (writer.depth <= 0)
            {
                throw CreateException(writer);
            }
            if (writer.depth-- > RecursionCheckDepth)
            {
                writer.PopRecursionStack();
            }
            writer.packedFieldNumber = 0; // ending the sub-item always wipes packed encoding
            if (value < 0)
            {                             // group - very simple append
                WriteHeaderCore(-value, WireType.EndGroup, writer);
                writer.wireType = WireType.None;
                return;
            }

            // so we're backfilling the length into an existing sequence
            int len;

            switch (style)
            {
            case PrefixStyle.Fixed32:
                len = (int)((writer.ioIndex - value) - 4);
                ProtoWriter.WriteInt32ToBuffer(len, writer.ioBuffer, value);
                break;

            case PrefixStyle.Fixed32BigEndian:
                len = (int)((writer.ioIndex - value) - 4);
                byte[] buffer = writer.ioBuffer;
                ProtoWriter.WriteInt32ToBuffer(len, buffer, value);
                // and swap the byte order
                byte b = buffer[value];
                buffer[value]     = buffer[value + 3];
                buffer[value + 3] = b;
                b = buffer[value + 1];
                buffer[value + 1] = buffer[value + 2];
                buffer[value + 2] = b;
                break;

            case PrefixStyle.Base128:
                // string - complicated because we only reserved one byte;
                // if the prefix turns out to need more than this then
                // we need to shuffle the existing data
                len = (int)((writer.ioIndex - value) - 1);
                int  offset = 0;
                uint tmp    = (uint)len;
                while ((tmp >>= 7) != 0)
                {
                    offset++;
                }
                if (offset == 0)
                {
                    writer.ioBuffer[value] = (byte)(len & 0x7F);
                }
                else
                {
                    DemandSpace(offset, writer);
                    byte[] blob = writer.ioBuffer;
                    Helpers.BlockCopy(blob, value + 1, blob, value + 1 + offset, len);
                    tmp = (uint)len;
                    do
                    {
                        blob[value++] = (byte)((tmp & 0x7F) | 0x80);
                    } while ((tmp >>= 7) != 0);
                    blob[value - 1]    = (byte)(blob[value - 1] & ~0x80);
                    writer.position64 += offset;
                    writer.ioIndex    += offset;
                }
                break;

            default:
                throw new ArgumentOutOfRangeException("style");
            }
            // and this object is no longer a blockage - also flush if sensible
            const int ADVISORY_FLUSH_SIZE = 1024;

            if (--writer.flushLock == 0 && writer.ioIndex >= ADVISORY_FLUSH_SIZE)
            {
                ProtoWriter.Flush(writer);
            }
        }