@@ -15,7 +15,12 @@ import kotlinx.serialization.modules.*
15
15
internal open class CborReader (override val cbor : Cbor , protected val parser : CborParserInterface ) : AbstractDecoder(),
16
16
CborDecoder {
17
17
18
- override fun decodeCborElement (): CborElement = CborTreeReader (cbor.configuration, parser).read()
18
+ override fun decodeCborElement (): CborElement =
19
+ when (parser) {
20
+ is CborParser -> CborTreeReader (cbor.configuration, parser).read()
21
+ is StructuredCborParser -> parser.element
22
+ }
23
+
19
24
20
25
protected var size = - 1
21
26
private set
@@ -154,13 +159,13 @@ internal open class CborReader(override val cbor: Cbor, protected val parser: Cb
154
159
}
155
160
156
161
internal class CborParser (private val input : ByteArrayInput , private val verifyObjectTags : Boolean ) : CborParserInterface {
157
- override var curByte: Int = - 1
162
+ var curByte: Int = - 1
158
163
159
164
init {
160
165
readByte()
161
166
}
162
167
163
- override fun readByte (): Int {
168
+ fun readByte (): Int {
164
169
curByte = input.read()
165
170
return curByte
166
171
}
@@ -549,106 +554,85 @@ private fun Iterable<ByteArray>.flatten(): ByteArray {
549
554
return output
550
555
}
551
556
552
-
557
+ private typealias ElementHolder = Pair <MutableList <ULong >, CborElement >
558
+ private val ElementHolder .tags: MutableList <ULong > get() = first
559
+ private val ElementHolder .element: CborElement get() = second
553
560
internal class StructuredCborParser (val element : CborElement , private val verifyObjectTags : Boolean ) : CborParserInterface {
554
- private var currentElement: CborElement = element
555
- private var mapIterator: Iterator <Map .Entry <CborElement , CborElement >>? = null
556
- private var listIterator: Iterator <CborElement >? = null
557
- private var currentMapEntry: Map .Entry <CborElement , CborElement >? = null
558
- private var currentListElement: CborElement ? = null
559
- private var collectedTags: ULongArray? = null
560
561
561
- // Implementation of properties needed for CborTreeReader
562
- override val curByte: Int
563
- get() = when (currentElement) {
564
- is CborPositiveInt -> 0 shl 5 // Major type 0: unsigned integer
565
- is CborNegativeInt -> 1 shl 5 // Major type 1: negative integer
566
- is CborByteString -> 2 shl 5 // Major type 2: byte string
567
- is CborString -> 3 shl 5 // Major type 3: text string
568
- is CborList -> 4 shl 5 // Major type 4: array
569
- is CborMap -> 5 shl 5 // Major type 5: map
570
- is CborBoolean -> if ((currentElement as CborBoolean ).value) 0xF5 else 0xF4
571
- is CborNull -> 0xF6
572
- is CborDouble -> NEXT_DOUBLE
573
- }
574
-
562
+
563
+ internal var current: ElementHolder = element.tags.toMutableList() to element
564
+ private var listIterator: Iterator <CborElement >? = null
565
+
575
566
// Implementation of methods needed for CborTreeReader
576
567
override fun nextTag (): ULong {
577
- // In the structured parser, we don't actually read tags from a stream
578
- // Instead, we return the first tag from the current element's tags
579
- val tags = currentElement.tags
580
- if (tags.isEmpty()) {
568
+ if (current.tags.isEmpty()) {
581
569
throw CborDecodingException (" Expected tag, but no tags found on current element" )
582
570
}
583
- return tags[ 0 ]
571
+ return current. tags.removeFirst()
584
572
}
585
573
586
- override fun readByte (): Int {
587
- // This is a no-op in the structured parser since we're not reading from a byte stream
588
- // We just return the current byte representation
589
- return curByte
574
+ override fun isNull () : Boolean {
575
+ // TODO this is a bit wonky! if we are inside a map, we want to skip over the key, and check the value,
576
+ // so the below call is not what it should be!
577
+ processTags(null )
578
+ return current.element is CborNull
590
579
}
591
580
592
- override fun isNull () = currentElement is CborNull
593
-
594
581
override fun isEnd () = when {
595
- mapIterator != null -> ! mapIterator!! .hasNext()
596
582
listIterator != null -> ! listIterator!! .hasNext()
597
583
else -> false
598
584
}
599
585
600
586
override fun end () {
601
587
// Reset iterators when ending a structure
602
- mapIterator = null
603
588
listIterator = null
604
- currentMapEntry = null
605
- currentListElement = null
606
589
}
607
-
590
+
608
591
override fun startArray (tags : ULongArray? ): Int {
609
592
processTags(tags)
610
- if (currentElement !is CborList ) {
611
- throw CborDecodingException (" Expected array, got ${currentElement ::class .simpleName} " )
593
+ if (current.element !is CborList ) {
594
+ throw CborDecodingException (" Expected array, got ${current.element ::class .simpleName} " )
612
595
}
613
596
614
- val list = currentElement as CborList
597
+ val list = current.element as CborList
615
598
listIterator = list.iterator()
616
599
return list.size
617
600
}
618
601
619
602
override fun startMap (tags : ULongArray? ): Int {
620
603
processTags(tags)
621
- if (currentElement !is CborMap ) {
622
- throw CborDecodingException (" Expected map, got ${currentElement ::class .simpleName} " )
604
+ if (current.element !is CborMap ) {
605
+ throw CborDecodingException (" Expected map, got ${current.element ::class .simpleName} " )
623
606
}
624
607
625
- val map = currentElement as CborMap
626
- mapIterator = map.entries.iterator()
627
- return map.size
608
+ val map = current.element as CborMap
609
+ // zip key, value, key, value, ... pairs to mirror byte-layout of CBOR map
610
+ listIterator = map.entries.flatMap { listOf (it.key, it.value) }.iterator()
611
+ return map.size // cbor map size is the size of the map, not the doubled size of the flattened pairs
628
612
}
629
613
630
614
override fun nextNull (tags : ULongArray? ): Nothing? {
631
615
processTags(tags)
632
- if (currentElement !is CborNull ) {
633
- throw CborDecodingException (" Expected null, got ${currentElement ::class .simpleName} " )
616
+ if (current.element !is CborNull ) {
617
+ throw CborDecodingException (" Expected null, got ${current.element ::class .simpleName} " )
634
618
}
635
619
return null
636
620
}
637
621
638
622
override fun nextBoolean (tags : ULongArray? ): Boolean {
639
623
processTags(tags)
640
- if (currentElement !is CborBoolean ) {
641
- throw CborDecodingException (" Expected boolean, got ${currentElement ::class .simpleName} " )
624
+ if (current.element !is CborBoolean ) {
625
+ throw CborDecodingException (" Expected boolean, got ${current.element ::class .simpleName} " )
642
626
}
643
- return (currentElement as CborBoolean ).value
627
+ return (current.element as CborBoolean ).value
644
628
}
645
629
646
630
override fun nextNumber (tags : ULongArray? ): Long {
647
631
processTags(tags)
648
- return when (currentElement ) {
649
- is CborPositiveInt -> (currentElement as CborPositiveInt ).value.toLong()
650
- is CborNegativeInt -> (currentElement as CborNegativeInt ).value
651
- else -> throw CborDecodingException (" Expected number, got ${currentElement ::class .simpleName} " )
632
+ return when (current.element ) {
633
+ is CborPositiveInt -> (current.element as CborPositiveInt ).value.toLong()
634
+ is CborNegativeInt -> (current.element as CborNegativeInt ).value
635
+ else -> throw CborDecodingException (" Expected number, got ${current.element ::class .simpleName} " )
652
636
}
653
637
}
654
638
@@ -657,34 +641,32 @@ internal class StructuredCborParser(val element: CborElement, private val verify
657
641
658
642
// Special handling for polymorphic serialization
659
643
// If we have a CborList with a string as first element, return that string
660
- if (currentElement is CborList && (currentElement as CborList ).isNotEmpty() && (currentElement as CborList )[0 ] is CborString ) {
661
- val stringElement = (currentElement as CborList )[0 ] as CborString
644
+ if (current.element is CborList && (current.element as CborList ).isNotEmpty() && (current.element as CborList )[0 ] is CborString ) {
645
+ val stringElement = (current.element as CborList )[0 ] as CborString
662
646
// Move to the next element (the map) for subsequent operations
663
- currentElement = (currentElement as CborList )[1 ]
647
+ current = (current.element as CborList )[ 1 ].tags.toMutableList() to (current.element as CborList )[1 ]
664
648
return stringElement.value
665
649
}
666
650
667
- if (currentElement !is CborString ) {
668
- throw CborDecodingException (" Expected string, got ${currentElement ::class .simpleName} " )
651
+ if (current.element !is CborString ) {
652
+ throw CborDecodingException (" Expected string, got ${current.element ::class .simpleName} " )
669
653
}
670
- return (currentElement as CborString ).value
654
+ return (current.element as CborString ).value
671
655
}
672
656
673
657
override fun nextByteString (tags : ULongArray? ): ByteArray {
674
658
processTags(tags)
675
- if (currentElement !is CborByteString ) {
676
- throw CborDecodingException (" Expected byte string, got ${currentElement ::class .simpleName} " )
659
+ if (current.element !is CborByteString ) {
660
+ throw CborDecodingException (" Expected byte string, got ${current.element ::class .simpleName} " )
677
661
}
678
- return (currentElement as CborByteString ).value
662
+ return (current.element as CborByteString ).value
679
663
}
680
664
681
665
override fun nextDouble (tags : ULongArray? ): Double {
682
666
processTags(tags)
683
- return when (currentElement) {
684
- is CborDouble -> (currentElement as CborDouble ).value
685
- is CborPositiveInt -> (currentElement as CborPositiveInt ).value.toDouble()
686
- is CborNegativeInt -> (currentElement as CborNegativeInt ).value.toDouble()
687
- else -> throw CborDecodingException (" Expected double, got ${currentElement::class .simpleName} " )
667
+ return when (current.element) {
668
+ is CborDouble -> (current.element as CborDouble ).value
669
+ else -> throw CborDecodingException (" Expected double, got ${current.element::class .simpleName} " )
688
670
}
689
671
}
690
672
@@ -695,7 +677,7 @@ internal class StructuredCborParser(val element: CborElement, private val verify
695
677
override fun nextTaggedStringOrNumber (): Triple <String ?, Long ?, ULongArray ?> {
696
678
val tags = processTags(null )
697
679
698
- return when (val key = currentMapEntry?.key ) {
680
+ return when (val key = current.element ) {
699
681
is CborString -> Triple (key.value, null , tags)
700
682
is CborPositiveInt -> Triple (null , key.value.toLong(), tags)
701
683
is CborNegativeInt -> Triple (null , key.value, tags)
@@ -704,29 +686,14 @@ internal class StructuredCborParser(val element: CborElement, private val verify
704
686
}
705
687
706
688
private fun processTags (tags : ULongArray? ): ULongArray? {
707
- val elementTags = currentElement.tags
708
-
689
+
709
690
// If we're in a list, advance to the next element
710
- if (listIterator != null && currentListElement == null && listIterator!! .hasNext()) {
711
- currentListElement = listIterator!! .next()
712
- currentElement = currentListElement!!
713
- }
714
-
715
- // If we're in a map, advance to the next entry if we're not processing a value
716
- if (mapIterator != null && currentMapEntry == null && mapIterator!! .hasNext()) {
717
- currentMapEntry = mapIterator!! .next()
718
- // We're now positioned at the key
719
- currentElement = currentMapEntry!! .key
720
- }
721
-
722
- // After processing a key in a map, move to the value for the next operation
723
- if (mapIterator != null && currentMapEntry != null && currentElement == currentMapEntry!! .key) {
724
- // We've processed the key, now move to the value
725
- currentElement = currentMapEntry!! .value
691
+ if (listIterator != null && listIterator!! .hasNext()) {
692
+ listIterator!! .next().let { current = it.tags.toMutableList() to it }
726
693
}
727
694
728
695
// Store collected tags for verification
729
- collectedTags = if (elementTags. isEmpty()) null else elementTags
696
+ val collectedTags = if (current.tags. isEmpty()) null else current.tags.toULongArray()
730
697
731
698
// Verify tags if needed
732
699
if (verifyObjectTags) {
@@ -749,12 +716,6 @@ internal class StructuredCborParser(val element: CborElement, private val verify
749
716
override fun skipElement (tags : ULongArray? ) {
750
717
// Process tags but don't do anything with the element
751
718
processTags(tags)
752
-
753
- // If we're in a map and have processed a key, move to the value
754
- if (mapIterator != null && currentMapEntry != null ) {
755
- currentElement = currentMapEntry!! .value
756
- currentMapEntry = null
757
- }
758
719
}
759
720
}
760
721
0 commit comments