public static CBORObject FromArray( Object arrObj, PODOptions options) { var arr = (Array)arrObj; int rank = arr.Rank; if (rank == 0) { return(CBORObject.NewArray()); } CBORObject obj = null; if (rank == 1) { // Most common case: the array is one-dimensional obj = CBORObject.NewArray(); int len = arr.GetLength(0); for (var i = 0; i < len; ++i) { obj.Add( CBORObject.FromObject( arr.GetValue(i), options)); } return(obj); } var index = new int[rank]; var dimensions = new int[rank]; for (var i = 0; i < rank; ++i) { dimensions[i] = arr.GetLength(i); } if (!FirstElement(index, dimensions)) { return(obj); } obj = BuildCBORArray(dimensions); do { CBORObject o = CBORObject.FromObject( arr.GetValue(index), options); SetCBORObject(obj, index, o); } while (NextElement(index, dimensions)); return(obj); }
private static void SetCBORObject( CBORObject cbor, int[] index, CBORObject obj) { CBORObject ret = cbor; for (var i = 0; i < index.Length - 1; ++i) { ret = ret[index[i]]; } int ilen = index[index.Length - 1]; while (ilen >= ret.Count) { { ret.Add(CBORObject.Null); } } ret[ilen] = obj; }
private static void SetCBORObject( CBORObject cbor, int[] index, CBORObject obj) { CBORObject ret = cbor; for (var i = 0; i < index.Length - 1; ++i) { ret = ret[index[i]]; } int ilen = index[index.Length - 1]; while (ilen >= ret.Count) { { ret.Add(CBORObject.Null); } } // TODO: Make Set(object, object) work with arrays // in next major version ret[ilen] = obj; }
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"); }
public CBORObject ReadForFirstByte(int firstbyte) { 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; long uadditional; CBORObject fixedObject; if (this.options.Ctap2Canonical) { if (additional >= 0x1c) { // NOTE: Includes stop byte and indefinite length data items throw new CBORException("Invalid canonical CBOR encountered"); } // Check if this represents a fixed object (NOTE: All fixed objects // comply with CTAP2 canonical CBOR). fixedObject = CBORObject.GetFixedObject(firstbyte); if (fixedObject != null) { return(fixedObject); } if (type == 6) { throw new CBORException("Tags not allowed in canonical CBOR"); } uadditional = ReadDataLength( this.stream, firstbyte, type, type == 7); if (type == 0) { return((uadditional >> 63) != 0 ? CBORObject.FromObject(ToUnsignedEInteger(uadditional)) : CBORObject.FromObject(uadditional)); } else if (type == 1) { return((uadditional >> 63) != 0 ? CBORObject.FromObject( ToUnsignedEInteger(uadditional).Add(1).Negate()) : CBORObject.FromObject((-uadditional) - 1L)); } else if (type == 7) { if (additional < 24) { return(CBORObject.FromSimpleValue(additional)); } else if (additional == 24 && uadditional < 32) { throw new CBORException("Invalid simple value encoding"); } else if (additional == 24) { return(CBORObject.FromSimpleValue((int)uadditional)); } else if (additional == 25) { return(CBORObject.FromFloatingPointBits(uadditional, 2)); } else if (additional == 26) { return(CBORObject.FromFloatingPointBits(uadditional, 4)); } else if (additional == 27) { return(CBORObject.FromFloatingPointBits(uadditional, 8)); } } else if (type >= 2 && type <= 5) { return(this.ReadStringArrayMap(type, uadditional)); } throw new CBORException("Unexpected data encountered"); } int expectedLength = CBORObject.GetExpectedLength(firstbyte); // Data checks if (expectedLength == -1) { // if the head byte is invalid throw new CBORException("Unexpected data encountered"); } // Check if this represents a fixed object 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); } if (additional == 31) { // Indefinite-length for major types 2 to 5 (other major // types were already handled in the call to // GetFixedLengthObject). switch (type) { case 2: { // 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" + ToUnsignedEInteger(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" + "\u0020than supported "); } data = ms.ToArray(); return(CBORObject.FromRaw(data)); } } case 3: { // 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" + ToUnsignedEInteger(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(CBORObject.FromRaw(builder.ToString())); } case 4: { CBORObject cbor = CBORObject.NewArray(); 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; } ++this.depth; CBORObject o = this.ReadForFirstByte( headByte); --this.depth; cbor.Add(o); ++vtindex; } return(cbor); } case 5: { CBORObject cbor = CBORObject.NewMap(); // 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); CBORObject value = this.ReadInternal(); --this.depth; if (!this.options.AllowDuplicateKeys) { if (cbor.ContainsKey(key)) { throw new CBORException("Duplicate key already exists"); } } cbor[key] = value; } return(cbor); } default: throw new CBORException("Unexpected data encountered"); } } EInteger bigintAdditional = EInteger.Zero; uadditional = ReadDataLength(this.stream, firstbyte, type); // 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 && type <= 5) { return(this.ReadStringArrayMap(type, uadditional)); } if (type == 6) // Tagged item { var haveFirstByte = false; var newFirstByte = -1; if (this.options.ResolveReferences && (uadditional >> 32) == 0) { // NOTE: HandleItemTag treats only certain tags up to 256 specially this.HandleItemTag(uadditional); } ++this.depth; CBORObject o = haveFirstByte ? this.ReadForFirstByte( newFirstByte) : this.ReadInternal(); --this.depth; if ((uadditional >> 63) != 0) { return(CBORObject.FromObjectAndTag(o, ToUnsignedEInteger(uadditional))); } if (uadditional < 65536) { if (this.options.ResolveReferences) { int uaddl = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 : (int)uadditional); switch (uaddl) { case 256: // string tag this.stringRefs.Pop(); break; case 25: // stringref tag if (o.IsTagged || o.Type != CBORType.Integer) { throw new CBORException("stringref must be an unsigned" + "\u0020integer"); } return(this.stringRefs.GetString(o.AsEIntegerValue())); } } return(CBORObject.FromObjectAndTag( o, (int)uadditional)); } return(CBORObject.FromObjectAndTag( o, (EInteger)uadditional)); } throw new CBORException("Unexpected data encountered"); }
private CBORObject ReadStringArrayMap(int type, long uadditional) { bool canonical = this.options.Ctap2Canonical; if (type == 2 || type == 3) // Byte string or text string { if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger" + "\u0020than supported"); } int hint = (uadditional > Int32.MaxValue || (uadditional >> 63) != 0) ? Int32.MaxValue : (int)uadditional; byte[] data = ReadByteData(this.stream, uadditional, null); if (type == 3) { if (!CBORUtilities.CheckUtf8(data)) { throw new CBORException("Invalid UTF-8"); } return(this.ObjectFromUtf8Array(data, hint)); } else { return(this.ObjectFromByteArray(data, hint)); } } if (type == 4) // Array { if (this.options.Ctap2Canonical && this.depth >= 4) { throw new CBORException("Depth too high in canonical CBOR"); } CBORObject cbor = CBORObject.NewArray(); if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger than" + "\u0020supported"); } if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) { throw new CBORException("Remaining data too small for array" + "\u0020length"); } ++this.depth; for (long i = 0; i < uadditional; ++i) { cbor.Add( this.ReadInternal()); } --this.depth; return(cbor); } if (type == 5) // Map, type 5 { if (this.options.Ctap2Canonical && this.depth >= 4) { throw new CBORException("Depth too high in canonical CBOR"); } CBORObject cbor = CBORObject.NewMap(); if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger than" + "\u0020supported"); } if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) { throw new CBORException("Remaining data too small for map" + "\u0020length"); } CBORObject lastKey = null; IComparer <CBORObject> comparer = CBORCanonical.Comparer; for (long i = 0; i < uadditional; ++i) { ++this.depth; CBORObject key = this.ReadInternal(); CBORObject value = this.ReadInternal(); --this.depth; if (this.options.Ctap2Canonical && lastKey != null) { int cmp = comparer.Compare(lastKey, key); if (cmp > 0) { throw new CBORException("Map key not in canonical order"); } else if (cmp == 0) { throw new CBORException("Duplicate map key"); } } if (!this.options.AllowDuplicateKeys) { if (cbor.ContainsKey(key)) { throw new CBORException("Duplicate key already exists"); } } lastKey = key; cbor[key] = value; } return(cbor); } return(null); }
public static CBORObject BuildCBORArray(int[] dimensions) { int zeroPos = dimensions.Length; for (var i = 0; i < dimensions.Length; ++i) { if (dimensions[i] == 0) { { zeroPos = i; } break; } } int arraydims = zeroPos - 1; if (arraydims <= 0) { return(CBORObject.NewArray()); } var stack = new CBORObject[zeroPos]; var index = new int[zeroPos]; var stackpos = 0; CBORObject ret = CBORObject.NewArray(); stack[0] = ret; index[0] = 0; for (var i = 0; i < dimensions[0]; ++i) { ret.Add(CBORObject.NewArray()); } ++stackpos; while (stackpos > 0) { int curindex = index[stackpos - 1]; if (curindex < stack[stackpos - 1].Count) { CBORObject subobj = stack[stackpos - 1][curindex]; if (stackpos < zeroPos) { stack[stackpos] = subobj; index[stackpos] = 0; for (var i = 0; i < dimensions[stackpos]; ++i) { subobj.Add(CBORObject.NewArray()); } ++index[stackpos - 1]; ++stackpos; } else { ++index[stackpos - 1]; } } else { --stackpos; } } return(ret); }