Beispiel #1
0
        public CBORObject ReadForFirstByte(
  int firstbyte,
  CBORTypeFilter filter)
        {
            if (this.depth > 500) {
            throw new CBORException("Too deeply nested");
              }
              if (firstbyte < 0) {
            throw new CBORException("Premature end of data");
              }
              if (firstbyte == 0xff) {
            throw new CBORException("Unexpected break code encountered");
              }
              int type = (firstbyte >> 5) & 0x07;
              int additional = firstbyte & 0x1f;
              int expectedLength = CBORObject.GetExpectedLength(firstbyte);
              // Data checks
              if (expectedLength == -1) {
            // if the head byte is invalid
            throw new CBORException("Unexpected data encountered");
              }
              if (filter != null) {
            // Check for valid major types if asked
            if (!filter.MajorTypeMatches(type)) {
              throw new CBORException("Unexpected data type encountered");
            }
            if (firstbyte >= 0xe0 && firstbyte <= 0xff && firstbyte != 0xf9 &&
            firstbyte != 0xfa && firstbyte != 0xfb) {
              if (!filter.NonFPSimpleValueAllowed()) {
            throw new CBORException("Unexpected data type encountered");
              }
            }
              }
              // Check if this represents a fixed object
              CBORObject fixedObject = CBORObject.GetFixedObject(firstbyte);
              if (fixedObject != null) {
            return fixedObject;
              }
              // Read fixed-length data
              byte[] data = null;
              if (expectedLength != 0) {
            data = new byte[expectedLength];
            // include the first byte because GetFixedLengthObject
            // will assume it exists for some head bytes
            data[0] = unchecked((byte)firstbyte);
            if (expectedLength > 1 &&
            this.stream.Read(data, 1, expectedLength - 1) != expectedLength
            - 1) {
              throw new CBORException("Premature end of data");
            }
            CBORObject cbor = CBORObject.GetFixedLengthObject(firstbyte, data);
            if (this.stringRefs != null && (type == 2 || type == 3)) {
              this.stringRefs.AddStringIfNeeded(cbor, expectedLength - 1);
            }
            if (this.addSharedRef && (type == 4 || type == 5)) {
              this.sharedRefs.AddObject(cbor);
            }
            return cbor;
              }
              var uadditional = (long)additional;
              EInteger bigintAdditional = EInteger.Zero;
              var hasBigAdditional = false;
              data = new byte[8];
              var lowAdditional = 0;
              switch (firstbyte & 0x1f) {
            case 24: {
            int tmp = this.stream.ReadByte();
            if (tmp < 0) {
              throw new CBORException("Premature end of data");
            }
            lowAdditional = tmp;
            uadditional = lowAdditional;
            break;
              }
            case 25: {
            if (this.stream.Read(data, 0, 2) != 2) {
              throw new CBORException("Premature end of data");
            }
            lowAdditional = ((int)(data[0] & (int)0xff)) << 8;
            lowAdditional |= (int)(data[1] & (int)0xff);
            uadditional = lowAdditional;
            break;
              }
            case 26: {
            if (this.stream.Read(data, 0, 4) != 4) {
              throw new CBORException("Premature end of data");
            }
            uadditional = ((long)(data[0] & (long)0xff)) << 24;
            uadditional |= ((long)(data[1] & (long)0xff)) << 16;
            uadditional |= ((long)(data[2] & (long)0xff)) << 8;
            uadditional |= (long)(data[3] & (long)0xff);
            break;
              }
            case 27: {
            if (this.stream.Read(data, 0, 8) != 8) {
              throw new CBORException("Premature end of data");
            }
            if ((((int)data[0]) & 0x80) != 0) {
              // Won't fit in a signed 64-bit number
              var uabytes = new byte[9];
              uabytes[0] = data[7];
              uabytes[1] = data[6];
              uabytes[2] = data[5];
              uabytes[3] = data[4];
              uabytes[4] = data[3];
              uabytes[5] = data[2];
              uabytes[6] = data[1];
              uabytes[7] = data[0];
              uabytes[8] = 0;
              hasBigAdditional = true;
              bigintAdditional = EInteger.FromBytes(uabytes, true);
            } else {
              uadditional = ((long)(data[0] & (long)0xff)) << 56;
              uadditional |= ((long)(data[1] & (long)0xff)) << 48;
              uadditional |= ((long)(data[2] & (long)0xff)) << 40;
              uadditional |= ((long)(data[3] & (long)0xff)) << 32;
              uadditional |= ((long)(data[4] & (long)0xff)) << 24;
              uadditional |= ((long)(data[5] & (long)0xff)) << 16;
              uadditional |= ((long)(data[6] & (long)0xff)) << 8;
              uadditional |= (long)(data[7] & (long)0xff);
            }
            break;
              }
              }
              // The following doesn't check for major types 0 and 1,
              // since all of them are fixed-length types and are
              // handled in the call to GetFixedLengthObject.
              if (type == 2) {  // Byte string
            if (additional == 31) {
              // Streaming byte string
              using (var ms = new MemoryStream()) {
            // Requires same type as this one
            while (true) {
              int nextByte = this.stream.ReadByte();
              if (nextByte == 0xff) {
                // break if the "break" code was read
                break;
              }
              long len = ReadDataLength(this.stream, nextByte, 2);
              if ((len >> 63) != 0 || len > Int32.MaxValue) {
                throw new CBORException("Length" + ToUnsignedBigInteger(len) +
                  " is bigger than supported ");
              }
              if (nextByte != 0x40) {  // NOTE: 0x40 means the empty byte string
                ReadByteData(this.stream, len, ms);
              }
            }
            if (ms.Position > Int32.MaxValue) {
              throw new
              CBORException("Length of bytes to be streamed is bigger than supported ");
            }
            data = ms.ToArray();
            return new CBORObject(
              CBORObject.CBORObjectTypeByteString,
              data);
              }
            } else {
              if (hasBigAdditional) {
            throw new CBORException("Length of " +
              CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
              }
              if (uadditional > Int32.MaxValue) {
            throw new CBORException("Length of " +
              CBORUtilities.LongToString(uadditional) +
              " is bigger than supported");
              }
              data = ReadByteData(this.stream, uadditional, null);
              var cbor = new CBORObject(CBORObject.CBORObjectTypeByteString, data);
              if (this.stringRefs != null) {
            int hint = (uadditional > Int32.MaxValue || hasBigAdditional) ?
            Int32.MaxValue : (int)uadditional;
            this.stringRefs.AddStringIfNeeded(cbor, hint);
              }
              return cbor;
            }
              }
              if (type == 3) {  // Text string
            if (additional == 31) {
              // Streaming text string
              var builder = new StringBuilder();
              while (true) {
            int nextByte = this.stream.ReadByte();
            if (nextByte == 0xff) {
              // break if the "break" code was read
              break;
            }
            long len = ReadDataLength(this.stream, nextByte, 3);
            if ((len >> 63) != 0 || len > Int32.MaxValue) {
              throw new CBORException("Length" + ToUnsignedBigInteger(len) +
                " is bigger than supported");
            }
            if (nextByte != 0x60) {  // NOTE: 0x60 means the empty string
              if (PropertyMap.ExceedsKnownLength(this.stream, len)) {
                // TODO: Remove following line in version 3.0
                PropertyMap.SkipStreamToEnd(this.stream);
                throw new CBORException("Premature end of data");
              }
              switch (
              DataUtilities.ReadUtf8(
              this.stream,
              (int)len,
              builder,
              false)) {
                case -1:
                  throw new CBORException("Invalid UTF-8");
                case -2:
                  throw new CBORException("Premature end of data");
              }
            }
              }
              return new CBORObject(
            CBORObject.CBORObjectTypeTextString,
            builder.ToString());
            } else {
              if (hasBigAdditional) {
            throw new CBORException("Length of " +
              CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
              }
              if (uadditional > Int32.MaxValue) {
            throw new CBORException("Length of " +
              CBORUtilities.LongToString(uadditional) +
              " is bigger than supported");
              }
              if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) {
            // TODO: Remove following line in version 3.0
            PropertyMap.SkipStreamToEnd(this.stream);
            throw new CBORException("Premature end of data");
              }
              var builder = new StringBuilder();
              switch (
              DataUtilities.ReadUtf8(
              this.stream,
              (int)uadditional,
              builder,
              false)) {
            case -1:
              throw new CBORException("Invalid UTF-8");
            case -2:
              throw new CBORException("Premature end of data");
              }
              var cbor = new CBORObject(
              CBORObject.CBORObjectTypeTextString,
              builder.ToString());
              if (this.stringRefs != null) {
            int hint = (uadditional > Int32.MaxValue || hasBigAdditional) ?
            Int32.MaxValue : (int)uadditional;
            this.stringRefs.AddStringIfNeeded(cbor, hint);
              }
              return cbor;
            }
              }
              if (type == 4) {  // Array
            CBORObject cbor = CBORObject.NewArray();
            if (this.addSharedRef) {
              this.sharedRefs.AddObject(cbor);
              this.addSharedRef = false;
            }
            if (additional == 31) {
              var vtindex = 0;
              // Indefinite-length array
              while (true) {
            int headByte = this.stream.ReadByte();
            if (headByte < 0) {
              throw new CBORException("Premature end of data");
            }
            if (headByte == 0xff) {
              // Break code was read
              break;
            }
            if (filter != null && !filter.ArrayIndexAllowed(vtindex)) {
              throw new CBORException("Array is too long");
            }
            ++this.depth;
            CBORObject o = this.ReadForFirstByte(
              headByte,
              filter == null ? null : filter.GetSubFilter(vtindex));
            --this.depth;
            cbor.Add(o);
            ++vtindex;
              }
              return cbor;
            }
            if (hasBigAdditional) {
              throw new CBORException("Length of " +
              CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
            }
            if (uadditional > Int32.MaxValue) {
              throw new CBORException("Length of " +
            CBORUtilities.LongToString(uadditional) +
            " is bigger than supported");
            }
            if (filter != null && !filter.ArrayLengthMatches(uadditional)) {
              throw new CBORException("Array is too long");
            }
            if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) {
              // TODO: Remove following line in version 3.0
              PropertyMap.SkipStreamToEnd(this.stream);
              throw new CBORException("Remaining data too small for array length");
            }
            ++this.depth;
            for (long i = 0; i < uadditional; ++i) {
              cbor.Add(
            this.Read(filter == null ? null : filter.GetSubFilter(i)));
            }
            --this.depth;
            return cbor;
              }
              if (type == 5) {  // Map, type 5
            CBORObject cbor = CBORObject.NewMap();
            if (this.addSharedRef) {
              this.sharedRefs.AddObject(cbor);
              this.addSharedRef = false;
            }
            if (additional == 31) {
              // Indefinite-length map
              while (true) {
            int headByte = this.stream.ReadByte();
            if (headByte < 0) {
              throw new CBORException("Premature end of data");
            }
            if (headByte == 0xff) {
              // Break code was read
              break;
            }
            ++this.depth;
            CBORObject key = this.ReadForFirstByte(headByte, null);
            CBORObject value = this.Read(null);
            --this.depth;
            if (this.policy == CBORDuplicatePolicy.Disallow) {
              if (cbor.ContainsKey(key)) {
                throw new CBORException("Duplicate key already exists: " + key);
              }
            }
            cbor[key] = value;
              }
              return cbor;
            }
            if (hasBigAdditional) {
              throw new CBORException("Length of " +
              CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
            }
            if (uadditional > Int32.MaxValue) {
              throw new CBORException("Length of " +
            CBORUtilities.LongToString(uadditional) +
            " is bigger than supported");
            }
            if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) {
            // TODO: Remove following line in version 3.0
            PropertyMap.SkipStreamToEnd(this.stream);
            throw new CBORException("Remaining data too small for map length");
            }
            for (long i = 0; i < uadditional; ++i) {
              ++this.depth;
              CBORObject key = this.Read(null);
              CBORObject value = this.Read(null);
              --this.depth;
              if (this.policy == CBORDuplicatePolicy.Disallow) {
            if (cbor.ContainsKey(key)) {
              throw new CBORException("Duplicate key already exists: " + key);
            }
              }
              cbor[key] = value;
            }
            return cbor;
              }
              if (type == 6) {  // Tagged item
            ICBORTag taginfo = null;
            var haveFirstByte = false;
            var newFirstByte = -1;
            var unnestedObject = false;
            CBORObject tagObject = null;
            if (!hasBigAdditional) {
              if (filter != null && !filter.TagAllowed(uadditional)) {
            throw new CBORException("Unexpected tag encountered: " +
                 uadditional);
              }
              int uad = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 :
            (int)uadditional);
              switch (uad) {
            case 256:
              // Tag 256: String namespace
              this.stringRefs = this.stringRefs ?? (new StringRefs());
              this.stringRefs.Push();
              break;
            case 25:
              // String reference
              if (this.stringRefs == null) {
                throw new CBORException("No stringref namespace");
              }

              break;
            case 28:
              // Shareable object
              newFirstByte = this.stream.ReadByte();
              if (newFirstByte < 0) {
                throw new CBORException("Premature end of data");
              }
              if (newFirstByte >= 0x80 && newFirstByte < 0xc0) {
                // Major types 4 and 5 (array and map)
                this.addSharedRef = true;
              } else if ((newFirstByte & 0xe0) == 0xc0) {
                // Major type 6 (tagged object)
                tagObject = new CBORObject(CBORObject.Undefined, 28, 0);
                this.sharedRefs.AddObject(tagObject);
              } else {
                // All other major types
                unnestedObject = true;
              }
              haveFirstByte = true;
              break;
              }

              taginfo = CBORObject.FindTagConverterLong(uadditional);
            } else {
              if (filter != null && !filter.TagAllowed(bigintAdditional)) {
            throw new CBORException("Unexpected tag encountered: " +
                 uadditional);
              }
              taginfo = CBORObject.FindTagConverter(bigintAdditional);
            }
            ++this.depth;
            CBORObject o = haveFirstByte ? this.ReadForFirstByte(
              newFirstByte,
              taginfo == null ? null : taginfo.GetTypeFilter()) :
            this.Read(taginfo == null ? null : taginfo.GetTypeFilter());
            --this.depth;
            if (hasBigAdditional) {
              return CBORObject.FromObjectAndTag(o, bigintAdditional);
            }
            if (uadditional < 65536) {
              int uaddl = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 :
            (int)uadditional);
              switch (uaddl) {
            case 256:
              // string tag
              this.stringRefs.Pop();
              break;
            case 25:
              // stringref tag
              return this.stringRefs.GetString(o.AsEInteger());
            case 28:
              // shareable object
              this.addSharedRef = false;
              if (unnestedObject) {
                this.sharedRefs.AddObject(o);
              }
              if (tagObject != null) {
              // TODO: Somehow implement sharable objects
              // without relying on Redefine method
              // tagObject.Redefine(o);
              // o = tagObject;
              }

              break;
            case 29:
              // shared object reference
              return this.sharedRefs.GetObject(o.AsEInteger());
              }

              return CBORObject.FromObjectAndTag(
            o,
            (int)uadditional);
            }
            return CBORObject.FromObjectAndTag(
              o,
              (EInteger)uadditional);
              }
              throw new CBORException("Unexpected data encountered");
        }
Beispiel #2
0
        public CBORObject ReadForFirstByte(
            int firstbyte,
            CBORTypeFilter filter)
        {
            if (this.depth > 500)
            {
                throw new CBORException("Too deeply nested");
            }
            if (firstbyte < 0)
            {
                throw new CBORException("Premature end of data");
            }
            if (firstbyte == 0xff)
            {
                throw new CBORException("Unexpected break code encountered");
            }
            int type           = (firstbyte >> 5) & 0x07;
            int additional     = firstbyte & 0x1f;
            int expectedLength = CBORObject.GetExpectedLength(firstbyte);

            // Data checks
            if (expectedLength == -1)
            {
                // if the head byte is invalid
                throw new CBORException("Unexpected data encountered");
            }
            if (filter != null)
            {
                // Check for valid major types if asked
                if (!filter.MajorTypeMatches(type))
                {
                    throw new CBORException("Unexpected data type encountered");
                }
                if (firstbyte >= 0xe0 && firstbyte <= 0xff && firstbyte != 0xf9 &&
                    firstbyte != 0xfa && firstbyte != 0xfb)
                {
                    if (!filter.NonFPSimpleValueAllowed())
                    {
                        throw new CBORException("Unexpected data type encountered");
                    }
                }
            }
            // Check if this represents a fixed object
            CBORObject fixedObject = CBORObject.GetFixedObject(firstbyte);

            if (fixedObject != null)
            {
                return(fixedObject);
            }
            // Read fixed-length data
            byte[] data = null;
            if (expectedLength != 0)
            {
                data = new byte[expectedLength];
                // include the first byte because GetFixedLengthObject
                // will assume it exists for some head bytes
                data[0] = unchecked ((byte)firstbyte);
                if (expectedLength > 1 &&
                    this.stream.Read(data, 1, expectedLength - 1) != expectedLength
                    - 1)
                {
                    throw new CBORException("Premature end of data");
                }
                CBORObject cbor = CBORObject.GetFixedLengthObject(firstbyte, data);
                if (this.stringRefs != null && (type == 2 || type == 3))
                {
                    this.stringRefs.AddStringIfNeeded(cbor, expectedLength - 1);
                }
                return(cbor);
            }
            var      uadditional      = (long)additional;
            EInteger bigintAdditional = EInteger.Zero;
            var      hasBigAdditional = false;

            data = new byte[8];
            var lowAdditional = 0;

            switch (firstbyte & 0x1f)
            {
            case 24: {
                int tmp = this.stream.ReadByte();
                if (tmp < 0)
                {
                    throw new CBORException("Premature end of data");
                }
                lowAdditional = tmp;
                uadditional   = lowAdditional;
                break;
            }

            case 25: {
                if (this.stream.Read(data, 0, 2) != 2)
                {
                    throw new CBORException("Premature end of data");
                }
                lowAdditional  = ((int)(data[0] & (int)0xff)) << 8;
                lowAdditional |= (int)(data[1] & (int)0xff);
                uadditional    = lowAdditional;
                break;
            }

            case 26: {
                if (this.stream.Read(data, 0, 4) != 4)
                {
                    throw new CBORException("Premature end of data");
                }
                uadditional  = ((long)(data[0] & (long)0xff)) << 24;
                uadditional |= ((long)(data[1] & (long)0xff)) << 16;
                uadditional |= ((long)(data[2] & (long)0xff)) << 8;
                uadditional |= (long)(data[3] & (long)0xff);
                break;
            }

            case 27: {
                if (this.stream.Read(data, 0, 8) != 8)
                {
                    throw new CBORException("Premature end of data");
                }
                if ((((int)data[0]) & 0x80) != 0)
                {
                    // Won't fit in a signed 64-bit number
                    var uabytes = new byte[9];
                    uabytes[0]       = data[7];
                    uabytes[1]       = data[6];
                    uabytes[2]       = data[5];
                    uabytes[3]       = data[4];
                    uabytes[4]       = data[3];
                    uabytes[5]       = data[2];
                    uabytes[6]       = data[1];
                    uabytes[7]       = data[0];
                    uabytes[8]       = 0;
                    hasBigAdditional = true;
                    bigintAdditional = EInteger.FromBytes(uabytes, true);
                }
                else
                {
                    uadditional  = ((long)(data[0] & (long)0xff)) << 56;
                    uadditional |= ((long)(data[1] & (long)0xff)) << 48;
                    uadditional |= ((long)(data[2] & (long)0xff)) << 40;
                    uadditional |= ((long)(data[3] & (long)0xff)) << 32;
                    uadditional |= ((long)(data[4] & (long)0xff)) << 24;
                    uadditional |= ((long)(data[5] & (long)0xff)) << 16;
                    uadditional |= ((long)(data[6] & (long)0xff)) << 8;
                    uadditional |= (long)(data[7] & (long)0xff);
                }
                break;
            }
            }
            // The following doesn't check for major types 0 and 1,
            // since all of them are fixed-length types and are
            // handled in the call to GetFixedLengthObject.
            if (type == 2) // Byte string
            {
                if (additional == 31)
                {
                    // Streaming byte string
                    using (var ms = new MemoryStream()) {
                        // Requires same type as this one
                        while (true)
                        {
                            int nextByte = this.stream.ReadByte();
                            if (nextByte == 0xff)
                            {
                                // break if the "break" code was read
                                break;
                            }
                            long len = ReadDataLength(this.stream, nextByte, 2);
                            if ((len >> 63) != 0 || len > Int32.MaxValue)
                            {
                                throw new CBORException("Length" + ToUnsignedBigInteger(len) +
                                                        " is bigger than supported ");
                            }
                            if (nextByte != 0x40) // NOTE: 0x40 means the empty byte string
                            {
                                ReadByteData(this.stream, len, ms);
                            }
                        }
                        if (ms.Position > Int32.MaxValue)
                        {
                            throw new
                                  CBORException("Length of bytes to be streamed is bigger than supported ");
                        }
                        data = ms.ToArray();
                        return(new CBORObject(
                                   CBORObject.CBORObjectTypeByteString,
                                   data));
                    }
                }
                else
                {
                    if (hasBigAdditional)
                    {
                        throw new CBORException("Length of " +
                                                CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
                    }
                    if (uadditional > Int32.MaxValue)
                    {
                        throw new CBORException("Length of " +
                                                CBORUtilities.LongToString(uadditional) +
                                                " is bigger than supported");
                    }
                    data = ReadByteData(this.stream, uadditional, null);
                    var cbor = new CBORObject(CBORObject.CBORObjectTypeByteString, data);
                    if (this.stringRefs != null)
                    {
                        int hint = (uadditional > Int32.MaxValue || hasBigAdditional) ?
                                   Int32.MaxValue : (int)uadditional;
                        this.stringRefs.AddStringIfNeeded(cbor, hint);
                    }
                    return(cbor);
                }
            }
            if (type == 3) // Text string
            {
                if (additional == 31)
                {
                    // Streaming text string
                    var builder = new StringBuilder();
                    while (true)
                    {
                        int nextByte = this.stream.ReadByte();
                        if (nextByte == 0xff)
                        {
                            // break if the "break" code was read
                            break;
                        }
                        long len = ReadDataLength(this.stream, nextByte, 3);
                        if ((len >> 63) != 0 || len > Int32.MaxValue)
                        {
                            throw new CBORException("Length" + ToUnsignedBigInteger(len) +
                                                    " is bigger than supported");
                        }
                        if (nextByte != 0x60) // NOTE: 0x60 means the empty string
                        {
                            if (PropertyMap.ExceedsKnownLength(this.stream, len))
                            {
                                throw new CBORException("Premature end of data");
                            }
                            switch (
                                DataUtilities.ReadUtf8(
                                    this.stream,
                                    (int)len,
                                    builder,
                                    false))
                            {
                            case -1:
                                throw new CBORException("Invalid UTF-8");

                            case -2:
                                throw new CBORException("Premature end of data");
                            }
                        }
                    }
                    return(new CBORObject(
                               CBORObject.CBORObjectTypeTextString,
                               builder.ToString()));
                }
                else
                {
                    if (hasBigAdditional)
                    {
                        throw new CBORException("Length of " +
                                                CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
                    }
                    if (uadditional > Int32.MaxValue)
                    {
                        throw new CBORException("Length of " +
                                                CBORUtilities.LongToString(uadditional) +
                                                " is bigger than supported");
                    }
                    if (PropertyMap.ExceedsKnownLength(this.stream, uadditional))
                    {
                        throw new CBORException("Premature end of data");
                    }
                    var builder = new StringBuilder();
                    switch (
                        DataUtilities.ReadUtf8(
                            this.stream,
                            (int)uadditional,
                            builder,
                            false))
                    {
                    case -1:
                        throw new CBORException("Invalid UTF-8");

                    case -2:
                        throw new CBORException("Premature end of data");
                    }
                    var cbor = new CBORObject(
                        CBORObject.CBORObjectTypeTextString,
                        builder.ToString());
                    if (this.stringRefs != null)
                    {
                        int hint = (uadditional > Int32.MaxValue || hasBigAdditional) ?
                                   Int32.MaxValue : (int)uadditional;
                        this.stringRefs.AddStringIfNeeded(cbor, hint);
                    }
                    return(cbor);
                }
            }
            if (type == 4) // Array
            {
                CBORObject cbor = CBORObject.NewArray();
                if (additional == 31)
                {
                    var vtindex = 0;
                    // Indefinite-length array
                    while (true)
                    {
                        int headByte = this.stream.ReadByte();
                        if (headByte < 0)
                        {
                            throw new CBORException("Premature end of data");
                        }
                        if (headByte == 0xff)
                        {
                            // Break code was read
                            break;
                        }
                        if (filter != null && !filter.ArrayIndexAllowed(vtindex))
                        {
                            throw new CBORException("Array is too long");
                        }
                        ++this.depth;
                        CBORObject o = this.ReadForFirstByte(
                            headByte,
                            filter == null ? null : filter.GetSubFilter(vtindex));
                        --this.depth;
                        cbor.Add(o);
                        ++vtindex;
                    }
                    return(cbor);
                }
                if (hasBigAdditional)
                {
                    throw new CBORException("Length of " +
                                            CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
                }
                if (uadditional > Int32.MaxValue)
                {
                    throw new CBORException("Length of " +
                                            CBORUtilities.LongToString(uadditional) +
                                            " is bigger than supported");
                }
                if (filter != null && !filter.ArrayLengthMatches(uadditional))
                {
                    throw new CBORException("Array is too long");
                }
                if (PropertyMap.ExceedsKnownLength(this.stream, uadditional))
                {
                    throw new CBORException("Remaining data too small for array length");
                }
                ++this.depth;
                for (long i = 0; i < uadditional; ++i)
                {
                    cbor.Add(
                        this.Read(filter == null ? null : filter.GetSubFilter(i)));
                }
                --this.depth;
                return(cbor);
            }
            if (type == 5) // Map, type 5
            {
                CBORObject cbor = CBORObject.NewMap();
                if (additional == 31)
                {
                    // Indefinite-length map
                    while (true)
                    {
                        int headByte = this.stream.ReadByte();
                        if (headByte < 0)
                        {
                            throw new CBORException("Premature end of data");
                        }
                        if (headByte == 0xff)
                        {
                            // Break code was read
                            break;
                        }
                        ++this.depth;
                        CBORObject key   = this.ReadForFirstByte(headByte, null);
                        CBORObject value = this.Read(null);
                        --this.depth;
                        if (this.policy == CBORDuplicatePolicy.Disallow)
                        {
                            if (cbor.ContainsKey(key))
                            {
                                throw new CBORException("Duplicate key already exists: " + key);
                            }
                        }
                        cbor[key] = value;
                    }
                    return(cbor);
                }
                if (hasBigAdditional)
                {
                    throw new CBORException("Length of " +
                                            CBORUtilities.BigIntToString(bigintAdditional) + " is bigger than supported");
                }
                if (uadditional > Int32.MaxValue)
                {
                    throw new CBORException("Length of " +
                                            CBORUtilities.LongToString(uadditional) +
                                            " is bigger than supported");
                }
                if (PropertyMap.ExceedsKnownLength(this.stream, uadditional))
                {
                    throw new CBORException("Remaining data too small for map length");
                }
                for (long i = 0; i < uadditional; ++i)
                {
                    ++this.depth;
                    CBORObject key   = this.Read(null);
                    CBORObject value = this.Read(null);
                    --this.depth;
                    if (this.policy == CBORDuplicatePolicy.Disallow)
                    {
                        if (cbor.ContainsKey(key))
                        {
                            throw new CBORException("Duplicate key already exists: " + key);
                        }
                    }
                    cbor[key] = value;
                }
                return(cbor);
            }
            if (type == 6) // Tagged item
            {
                ICBORTag taginfo       = null;
                var      haveFirstByte = false;
                var      newFirstByte  = -1;
                if (!hasBigAdditional)
                {
                    if (filter != null && !filter.TagAllowed(uadditional))
                    {
                        throw new CBORException("Unexpected tag encountered: " +
                                                uadditional);
                    }
                    int uad = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 :
                                                          (int)uadditional);
                    switch (uad)
                    {
                    case 256:
                        // Tag 256: String namespace
                        this.stringRefs = this.stringRefs ?? (new StringRefs());
                        this.stringRefs.Push();
                        break;

                    case 25:
                        // String reference
                        if (this.stringRefs == null)
                        {
                            throw new CBORException("No stringref namespace");
                        }
                        break;

                    case 28:
                    case 29:
                        this.hasSharableObjects = true;
                        break;
                    }

                    taginfo = CBORObject.FindTagConverterLong(uadditional);
                }
                else
                {
                    if (filter != null && !filter.TagAllowed(bigintAdditional))
                    {
                        throw new CBORException("Unexpected tag encountered: " +
                                                uadditional);
                    }
                    taginfo = CBORObject.FindTagConverter(bigintAdditional);
                }
                ++this.depth;
                CBORObject o = haveFirstByte ? this.ReadForFirstByte(
                    newFirstByte,
                    taginfo == null ? null : taginfo.GetTypeFilter()) :
                               this.Read(taginfo == null ? null : taginfo.GetTypeFilter());
                --this.depth;
                if (hasBigAdditional)
                {
                    return(CBORObject.FromObjectAndTag(o, bigintAdditional));
                }
                if (uadditional < 65536)
                {
                    int uaddl = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 :
                                                            (int)uadditional);
                    switch (uaddl)
                    {
                    case 256:
                        // string tag
                        this.stringRefs.Pop();
                        break;

                    case 25:
                        // stringref tag
                        return(this.stringRefs.GetString(o.AsEInteger()));
                    }

                    return(CBORObject.FromObjectAndTag(
                               o,
                               (int)uadditional));
                }
                return(CBORObject.FromObjectAndTag(
                           o,
                           (EInteger)uadditional));
            }
            throw new CBORException("Unexpected data encountered");
        }