progress...
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 09a220d..1115fa9 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -72,7 +72,7 @@
 DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
 {
    // Check in DecodeNesting_Descend and never having
-   // QCBOR_MAX_ARRAY_NESTING > 255 gaurantee cast is safe
+   // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
    return (uint8_t)(pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]));
 }
 
@@ -1031,6 +1031,7 @@
 
 /*
  Public function, see header qcbor/qcbor_decode.h file
+ TODO: correct this comment
  */
 QCBORError QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me,
                                          QCBORItem *pDecodedItem,
@@ -1038,11 +1039,9 @@
 {
    // Stack ptr/int: 2, QCBORItem : 64
 
-   // The public entry point for fetching and parsing the next QCBORItem.
-   // All the CBOR parsing work is here and in subordinate calls.
    QCBORError nReturn;
 
-   // Check if there are an
+   // Check if there are an TODO: incomplete
    if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && !DecodeNesting_IsNested(&(me->nesting))) {
       nReturn = QCBOR_ERR_NO_MORE_ITEMS;
       goto Done;
@@ -1424,7 +1423,7 @@
  - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
  ends of maps and arrays. It tracks descending into and ascending
  out of maps/arrays. It processes all breaks that terminate
- maps and arrays.
+ indefinite length maps and arrays.
 
  - GetNext_MapEntry -- This handles the combining of two
  items, the label and the data, that make up a map entry.
@@ -1715,3 +1714,345 @@
 
    return QCBOR_SUCCESS;
 }
+
+
+
+
+/*
+ * Public function. See qcbor_util.h
+ */
+static QCBORError
+ConsumeItem(QCBORDecodeContext *pMe,
+            const QCBORItem    *pItemToConsume,
+            uint_fast8_t       *puNextNestLevel)
+{
+    QCBORError nReturn;
+    QCBORItem  Item;
+
+    if(pItemToConsume->uDataType == QCBOR_TYPE_MAP ||
+       pItemToConsume->uDataType == QCBOR_TYPE_ARRAY) {
+        /* There is only real work to do for maps and arrays */
+
+        /* This works for definite and indefinite length
+         * maps and arrays by using the nesting level
+         */
+        do {
+            nReturn = QCBORDecode_GetNext(pMe, &Item);
+            if(nReturn != QCBOR_SUCCESS) {
+                goto Done;
+            }
+        } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
+
+        if(puNextNestLevel != NULL) {
+            *puNextNestLevel = Item.uNextNestLevel;
+        }
+        nReturn = QCBOR_SUCCESS;
+
+    } else {
+        /* item_to_consume is not a map or array */
+        if(puNextNestLevel != NULL) {
+            /* Just pass the nesting level through */
+            *puNextNestLevel = pItemToConsume->uNextNestLevel;
+        }
+        nReturn = QCBOR_SUCCESS;
+    }
+
+Done:
+    return nReturn;
+}
+
+
+/*
+ * Public function. qcbor_util.h
+ */
+QCBORError
+GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemArray, size_t *puOffset)
+{
+    QCBORItem  *pIterator;
+    QCBORError  nReturn;
+
+    // TODO: check we are in map mode
+    
+    /* Clear structure holding the items found */
+    for(pIterator = pItemArray; pIterator->uLabelType != 0; pIterator++) {
+        pIterator->uDataType = QCBOR_TYPE_NONE;
+    }
+    
+    // Save the cursor and such used for pre-order traversal
+    const size_t   uSave        = UsefulInputBuf_Tell(&(pMe->InBuf));
+    const uint16_t uSaveCount   = pMe->nesting.pCurrent->uCount;
+    const void    *pSaveCurrent = pMe->nesting.pCurrent;
+    
+    if(pMe->nesting.pCurrent->uCount != UINT16_MAX) {
+        pMe->nesting.pCurrent->uCount = 0;
+    }
+    
+    UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
+
+    /* Loop over all the items in the map. They could be
+     * deeply nested and this should handle both definite
+     * and indefinite length maps and arrays, so this
+     * adds some complexity. */
+    const uint8_t uMapNestLevel = DecodeNesting_GetLevel(&(pMe->nesting));
+
+    while(1) {
+        QCBORItem Item;
+        
+        const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+        if((nReturn = QCBORDecode_GetNext(pMe, &Item)) != QCBOR_SUCCESS) {
+            /* Got non-well-formed CBOR */
+            goto Done;
+        }
+       
+       // Loop over all the items to check this item against
+       for(pIterator = pItemArray; pIterator->uLabelType != 0; pIterator++) {
+          if(Item.uLabelType == QCBOR_TYPE_INT64) {
+             if(Item.label.int64 != pIterator->label.int64) {
+                continue; // Label didn't match
+             }
+          } else if(Item.uLabelType == QCBOR_TYPE_TEXT_STRING) {
+             if(UsefulBuf_Compare(Item.label.string, pIterator->label.string)) {
+                continue; // Label didn't match
+             }
+          } else {
+             // Some label type that isn't supported; ignore it
+             continue;
+          }
+          // A label match has been found
+          if(pIterator->uDataType != QCBOR_TYPE_NONE) {
+               nReturn = QCBOR_ERR_DUPLICATE_LABEL;
+               goto Done;
+           }
+           *pIterator = Item;
+           if(puOffset) {
+               *puOffset = uOffset;
+           }
+       }
+
+        /* Only looking at top-level data items, so just consume any
+         * map or array encountered.*/
+        uint_fast8_t uNextNestLevel;
+
+        nReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
+        if(nReturn) {
+            goto Done;
+        }
+        if(uNextNestLevel < uMapNestLevel) {
+            nReturn = QCBOR_SUCCESS;
+            /* Got all the items in the map. This is the non-error exit
+             * from the loop. */
+            // Cast OK because encoded CBOR is limited to UINT32_MAX
+            pMe->uMapEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
+            // record the offset here for exit to save CPU time
+            break;
+        }
+    }
+
+Done:
+    // Restore cursor for pre-order traversal
+    pMe->nesting.pCurrent         = (struct nesting_decode_level *)pSaveCurrent;
+    pMe->nesting.pCurrent->uCount = uSaveCount;
+    UsefulInputBuf_Seek(&(pMe->InBuf), uSave);
+    
+    return nReturn;
+}
+
+void QCBORDecode_ExitMap(QCBORDecodeContext *pMe)
+{
+    size_t uEndOffset;
+    
+    if(pMe->uMapEndOffset) {
+        uEndOffset = pMe->uMapEndOffset;
+    } else {
+        /* Call qcbor_util_get_items_in_map to do the work. */
+        QCBORItem Dummy;
+        
+        Dummy.uDataType = QCBOR_TYPE_NONE;
+        
+        QCBORError nReturn = GetItemsInMap(pMe, &Dummy, &uEndOffset);
+
+        (void)nReturn; // TODO:
+    }
+    UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
+    
+    DecodeNesting_DecrementCount(&(pMe->nesting));
+}
+
+
+QCBORError QCBORDecode_GetItemInMap(QCBORDecodeContext *pMe,
+                             int64_t nLabel,
+                             uint8_t uQcborType,
+                             QCBORItem *pItem)
+{
+    /* Call qcbor_util_get_items_in_map to do the work. */
+    QCBORItem One[2];
+    
+    One[0].uDataType = QCBOR_TYPE_INT64;
+    One[0].label.int64 = nLabel;
+    One[1].uDataType = QCBOR_TYPE_NONE; // Indicates end of array
+    
+    QCBORError nReturn = GetItemsInMap(pMe, One, NULL);
+    if(nReturn) {
+        return nReturn;
+    }
+    
+    if(One[0].uDataType == QCBOR_TYPE_NONE) {
+        return QCBOR_ERR_NOT_FOUND;
+    }
+
+    if(One[0].uDataType != uQcborType) {
+        return QCBOR_ERR_UNEXPECTED_TYPE;
+    }
+    
+    *pItem = One[0];
+    
+    return QCBOR_SUCCESS;
+}
+
+
+QCBORError QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
+                             const char *szLabel,
+                             uint8_t uQcborType,
+                             QCBORItem *pItem)
+{
+    /* Call qcbor_util_get_items_in_map to do the work. */
+    QCBORItem One[2];
+    
+    One[0].uDataType = QCBOR_TYPE_TEXT_STRING;
+   One[0].label.string = UsefulBuf_FromSZ(szLabel);
+    One[1].uDataType = QCBOR_TYPE_NONE; // Indicates end of array
+    
+    QCBORError nReturn = GetItemsInMap(pMe, One, NULL);
+    if(nReturn) {
+        return nReturn;
+    }
+    
+    if(One[0].uDataType == QCBOR_TYPE_NONE) {
+        return QCBOR_ERR_NOT_FOUND;
+    }
+
+    if(One[0].uDataType != uQcborType) {
+        return QCBOR_ERR_UNEXPECTED_TYPE;
+    }
+    
+    *pItem = One[0];
+    
+    return QCBOR_SUCCESS;
+}
+
+
+void QCBORDecode_GetBstrInMap(QCBORDecodeContext *pMe, int64_t nLabel, UsefulBufC *pBstr)
+{
+    // TODO: error handling
+    QCBORItem Item;
+    QCBORDecode_GetItemInMap(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item);
+    *pBstr = Item.val.string;
+}
+
+
+QCBORError QCBORDecode_EnterMapInMap(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+    QCBORItem One[2];
+    
+    One[0].uDataType = QCBOR_TYPE_INT64;
+    One[0].label.int64 = nLabel;
+    One[1].uDataType = QCBOR_TYPE_NONE;
+    
+    size_t uOffset;
+    
+    QCBORError r = GetItemsInMap(pMe, One, &uOffset);
+    
+    if(r) {
+        return r;
+    }
+    
+    if(One[0].uDataType != QCBOR_TYPE_MAP) {
+        return QCBOR_ERR_UNEXPECTED_TYPE;
+    }
+    
+    UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
+    
+    DecodeNesting_Descend(&(pMe->nesting), &One[1]);
+
+    pMe->nesting.pCurrent->uOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
+    pMe->nesting.pCurrent->uMapMode = 1;
+    
+    return 0;
+}
+
+
+QCBORError QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char  *szLabel)
+{
+   QCBORItem One[2];
+    
+   One[0].uDataType = QCBOR_TYPE_TEXT_STRING;
+   One[0].label.string = UsefulBuf_FromSZ(szLabel);
+   One[1].uDataType = QCBOR_TYPE_NONE;
+    
+    size_t uOffset;
+    
+    QCBORError nReturn = GetItemsInMap(pMe, One, &uOffset);
+    
+    if(nReturn) {
+        return nReturn;
+    }
+    
+    if(One[0].uDataType != QCBOR_TYPE_MAP) {
+        return QCBOR_ERR_UNEXPECTED_TYPE;
+    }
+    
+    UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
+    
+    DecodeNesting_Descend(&(pMe->nesting), &One[1]);
+
+    pMe->nesting.pCurrent->uOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
+    pMe->nesting.pCurrent->uMapMode = 1;
+    
+    return 0;
+}
+
+
+
+/* Next item must be map or this generates an error */
+QCBORError QCBORDecode_EnterMap(QCBORDecodeContext *pMe)
+{
+    QCBORItem Item;
+    
+    /* Get the data item that is the map that is being searched */
+    QCBORDecode_GetNext(pMe, &Item);
+    if(Item.uDataType != QCBOR_TYPE_MAP) {
+        return QCBOR_ERR_UNEXPECTED_TYPE;
+    }
+     
+    
+    // Cast to uint32_t is safe because QCBOR onl works on data < UINT32_MAX
+    pMe->nesting.pCurrent->uOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
+    pMe->nesting.pCurrent->uMapMode = 1;
+
+
+    return QCBOR_SUCCESS;
+}
+
+
+
+QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
+{
+    return GetItemsInMap(pCtx, pItemList, NULL);
+}
+
+
+void QCBORDecode_GetIntInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, int64_t *pInt)
+{
+   // TODO: error handling
+   QCBORItem Item;
+   QCBORDecode_GetItemInMapSZ(pMe,szLabel, QCBOR_TYPE_INT64, &Item);
+   *pInt = Item.val.int64;
+}
+
+
+void QCBORDecode_RewindMap(QCBORDecodeContext *pCtxt)
+{
+   
+   
+}