@@ -15,7 +15,12 @@ import kotlinx.serialization.modules.*
1515internal open class CborReader (override val cbor : Cbor , protected val parser : CborParserInterface ) : AbstractDecoder(),
1616 CborDecoder {
1717
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+
1924
2025 protected var size = - 1
2126 private set
@@ -154,13 +159,13 @@ internal open class CborReader(override val cbor: Cbor, protected val parser: Cb
154159}
155160
156161internal class CborParser (private val input : ByteArrayInput , private val verifyObjectTags : Boolean ) : CborParserInterface {
157- override var curByte: Int = - 1
162+ var curByte: Int = - 1
158163
159164 init {
160165 readByte()
161166 }
162167
163- override fun readByte (): Int {
168+ fun readByte (): Int {
164169 curByte = input.read()
165170 return curByte
166171 }
@@ -549,106 +554,85 @@ private fun Iterable<ByteArray>.flatten(): ByteArray {
549554 return output
550555}
551556
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
553560internal 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
560561
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+
575566 // Implementation of methods needed for CborTreeReader
576567 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()) {
581569 throw CborDecodingException (" Expected tag, but no tags found on current element" )
582570 }
583- return tags[ 0 ]
571+ return current. tags.removeFirst()
584572 }
585573
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
590579 }
591580
592- override fun isNull () = currentElement is CborNull
593-
594581 override fun isEnd () = when {
595- mapIterator != null -> ! mapIterator!! .hasNext()
596582 listIterator != null -> ! listIterator!! .hasNext()
597583 else -> false
598584 }
599585
600586 override fun end () {
601587 // Reset iterators when ending a structure
602- mapIterator = null
603588 listIterator = null
604- currentMapEntry = null
605- currentListElement = null
606589 }
607-
590+
608591 override fun startArray (tags : ULongArray? ): Int {
609592 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} " )
612595 }
613596
614- val list = currentElement as CborList
597+ val list = current.element as CborList
615598 listIterator = list.iterator()
616599 return list.size
617600 }
618601
619602 override fun startMap (tags : ULongArray? ): Int {
620603 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} " )
623606 }
624607
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
628612 }
629613
630614 override fun nextNull (tags : ULongArray? ): Nothing? {
631615 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} " )
634618 }
635619 return null
636620 }
637621
638622 override fun nextBoolean (tags : ULongArray? ): Boolean {
639623 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} " )
642626 }
643- return (currentElement as CborBoolean ).value
627+ return (current.element as CborBoolean ).value
644628 }
645629
646630 override fun nextNumber (tags : ULongArray? ): Long {
647631 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} " )
652636 }
653637 }
654638
@@ -657,34 +641,32 @@ internal class StructuredCborParser(val element: CborElement, private val verify
657641
658642 // Special handling for polymorphic serialization
659643 // 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
662646 // 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 ]
664648 return stringElement.value
665649 }
666650
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} " )
669653 }
670- return (currentElement as CborString ).value
654+ return (current.element as CborString ).value
671655 }
672656
673657 override fun nextByteString (tags : ULongArray? ): ByteArray {
674658 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} " )
677661 }
678- return (currentElement as CborByteString ).value
662+ return (current.element as CborByteString ).value
679663 }
680664
681665 override fun nextDouble (tags : ULongArray? ): Double {
682666 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} " )
688670 }
689671 }
690672
@@ -695,7 +677,7 @@ internal class StructuredCborParser(val element: CborElement, private val verify
695677 override fun nextTaggedStringOrNumber (): Triple <String ?, Long ?, ULongArray ?> {
696678 val tags = processTags(null )
697679
698- return when (val key = currentMapEntry?.key ) {
680+ return when (val key = current.element ) {
699681 is CborString -> Triple (key.value, null , tags)
700682 is CborPositiveInt -> Triple (null , key.value.toLong(), tags)
701683 is CborNegativeInt -> Triple (null , key.value, tags)
@@ -704,29 +686,14 @@ internal class StructuredCborParser(val element: CborElement, private val verify
704686 }
705687
706688 private fun processTags (tags : ULongArray? ): ULongArray? {
707- val elementTags = currentElement.tags
708-
689+
709690 // 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 }
726693 }
727694
728695 // 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()
730697
731698 // Verify tags if needed
732699 if (verifyObjectTags) {
@@ -749,12 +716,6 @@ internal class StructuredCborParser(val element: CborElement, private val verify
749716 override fun skipElement (tags : ULongArray? ) {
750717 // Process tags but don't do anything with the element
751718 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- }
758719 }
759720}
760721
0 commit comments