Finish up OpenBytes -- error handing, documentation...
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index e1fe0a8..6c95c4b 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -1,6 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2018-2022, Laurence Lundblade.
  Copyright (c) 2021, Arm Limited.
  All rights reserved.
 
@@ -314,7 +314,8 @@
    QCBOR_ERR_TOO_MANY_CLOSES = 7,
 
    /** During encoding the number of array or map opens was not
-       matched by the number of closes. */
+       matched by the number of closes. Also occurs with opened
+       byte strings that are not closed. */
    QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 8,
 
 #define QCBOR_START_OF_NOT_WELL_FORMED_ERRORS 9
@@ -489,7 +490,7 @@
        non-CBOR reason */
    QCBOR_ERR_CALLBACK_FAIL = 38,
 
-   /** This error code is deprecated. Instead, 
+   /** This error code is deprecated. Instead,
        \ref QCBOR_ERR_HALF_PRECISION_DISABLED,
        \ref QCBOR_ERR_HW_FLOAT_DISABLED or \ref QCBOR_ERR_ALL_FLOAT_DISABLED
        is returned depending on the specific floating-point functionality
@@ -526,9 +527,9 @@
        floating point numbers is not possible. */
    QCBOR_ERR_ALL_FLOAT_DISABLED = 46,
 
-   /** During encode, the amount given to QCBOREncode_CloseBytes() was
-       past the end of what was returned by QCBOREncode_OpenBytes(). */
-   QCBOR_ERR_ADVANCE_TOO_FAR = 47
+   /** During encode, opening a byte string while a byte string is open
+       is not allowed. . */
+   QCBOR_ERR_OPEN_BYTE_STRING = 47
 
    /* This is stored in uint8_t; never add values > 255 */
 } QCBORError;
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 095cb96..1b1b62c 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -843,33 +843,34 @@
 /**
  @brief Set up to write a byte string value directly to encoded output.
 
- @param[in] pCtx   The encoding context to add the bytes to.
+ @param[in] pCtx     The encoding context to add the bytes to.
  @param[out] pPlace  Pointer and length of place to write byte string value.
 
- See QCBOREncode_AddBytes() for the usual way to output a byte string.
+ QCBOREncode_AddBytes() is the normal way to encode a byte string.
+ This is for special cases and by passes some of the pointer safety.
 
- The purpose of this is to output the bytes that make
- up a byte string value directly to the QCBOR output buffer so you don't
- need to have a copy of it in memory. This is particularly useful
- if the byte string is large, for example the encrypted payload
- of a COSE_Encrypt message. The payload encryption algorithm can
- output directly to the encoded CBOR buffer.
+ The purpose of this is to output the bytes that make up a byte string
+ value directly to the QCBOR output buffer so you don't need to have a
+ copy of it in memory. This is particularly useful if the byte string
+ is large, for example, the encrypted payload of a COSE_Encrypt
+ message. The payload encryption algorithm can output directly to the
+ encoded CBOR buffer.
 
  The pointer in \c pPlace is where to start writing. Writing is just
- copying bytes to the location by the pointer in \c pPlace.
- Writing past
- the length in \c pPlace will be writing off the end of the
+ copying bytes to the location by the pointer in \c pPlace.  Writing
+ past the length in \c pPlace will be writing off the end of the
  output buffer.
 
- If there is no room in the output buffer NULLUsefulBuf will be returned and
- there is no need to call QCBOREncode_CloseBytes().
+ If there is no room in the output buffer @ref NULLUsefulBuf will be
+ returned and there is no need to call QCBOREncode_CloseBytes().
 
  The byte string must be closed by calling QCBOREncode_CloseBytes().
 
- TODO: finish this documentation, write the implementation, test the code.
-
+ Warning: this bypasses some of the usual checks provided by QCBOR
+ against writing off the end of the encoded output buffer.
  */
-void QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace);
+void
+QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace);
 
 static void
 QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBuf *pPlace);
@@ -881,14 +882,15 @@
 /**
   @brief Close out a byte string written directly to encoded output.
 
-  @param[in] pCtx   The encoding context to add the bytes to.
+  @param[in] pCtx      The encoding context to add the bytes to.
   @param[out] uAmount  The number of bytes written, the length of the byte string.
 
- This inserts a CBOR header at the front of the byte string value to make
- it a well-formed byte string.
+ This closes out a call to QCBOREncode_OpenBytes().  This inserts a
+ CBOR header at the front of the byte string value to make it a
+ well-formed byte string.
 
- If there was no call to QCBOREncode_OpenBytes() then @ref QCBOR_ERR_TOO_MANY_CLOSES is
- set.
+ If there was no call to QCBOREncode_OpenBytes() then
+ @ref QCBOR_ERR_TOO_MANY_CLOSES is set.
  */
 void QCBOREncode_CloseBytes(QCBOREncodeContext *pCtx, size_t uAmount);
 
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 6cfeb8b..af0e38b 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -941,7 +941,15 @@
 {
    *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
    if(!UsefulBuf_IsNULL(*pPlace)){
-      QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+      uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
+      if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
+         pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
+         return;
+      }
+#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+   QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
    }
 }
 
@@ -949,11 +957,11 @@
 /*
  * Public function for closing a byte string. See qcbor/qcbor_encode.h
  */
-void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, size_t uAmount)
+void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
 {
    UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
    if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
-      pMe->uError = QCBOR_ERR_ADVANCE_TOO_FAR;
+      /* Advance too far. Normal off-end error handling in effect here. */
       return;
    }
 
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index ccd07b8..3ab3557 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -815,7 +815,7 @@
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
-const char *UBAdvanceTest()
+const char *UBAdvanceTest(void)
 {
    #define ADVANCE_TEST_SIZE 10
    UsefulOutBuf_MakeOnStack(UOB, ADVANCE_TEST_SIZE);
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index c440fb0..0b6b979 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -1,6 +1,6 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2018-2022, Laurence Lundblade.
  Copyright (c) 2021, Arm Limited.
  All rights reserved.
 
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 196733f..fd9f544 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -2877,43 +2877,46 @@
 }
 
 
-
-
-static const uint8_t spExpectedBytes[] = {
+static const uint8_t spExpectedForOpenBytes[] = {
    0x50, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
    0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
    0x78
 };
 
-int32_t OpenCloseBytesTest(void)
+static const uint8_t spExpectedForOpenBytes2[] = {
+   0xA4, 0x0A, 0x16, 0x14, 0x42, 0x78, 0x78, 0x66,
+   0x74, 0x68, 0x69, 0x72, 0x74, 0x79, 0x43, 0x79,
+   0x79, 0x79, 0x18, 0x28, 0x81, 0x40
+};
+
+int32_t
+OpenCloseBytesTest(void)
 {
-   UsefulBuf_MAKE_STACK_UB(  TestBuf, 20);
+   UsefulBuf_MAKE_STACK_UB(   TestBuf,  20);
+   UsefulBuf_MAKE_STACK_UB(   TestBuf2, 30);
    QCBOREncodeContext         EC;
    UsefulBuf                  Place;
    UsefulBufC                 Encoded;
    QCBORError                 uErr;
 
+   /* Normal use case -- add a byte string that fits */
    QCBOREncode_Init(&EC, TestBuf);
-
    QCBOREncode_OpenBytes(&EC, &Place);
    if(Place.ptr != TestBuf.ptr ||
       Place.len != TestBuf.len) {
       return 1;
    }
-
    Place.len -= 4;
    UsefulBuf_Set(Place, 'x');
-
    QCBOREncode_CloseBytes(&EC, Place.len);
-
    QCBOREncode_Finish(&EC, &Encoded);
-
    if(UsefulBuf_Compare(Encoded,
-                        UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedBytes))) {
+                        UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedForOpenBytes))) {
       return 2;
    }
 
 
+   /* Open a byte string with no room left */
    QCBOREncode_Init(&EC, TestBuf);
    QCBOREncode_AddSZString(&EC, "0123456789012345678");
    QCBOREncode_OpenBytes(&EC, &Place);
@@ -2922,25 +2925,72 @@
       return 3;
    }
 
-   QCBOREncode_Init(&EC, TestBuf);
-   QCBOREncode_AddSZString(&EC, "012345678");
-   QCBOREncode_CloseBytes(&EC, 1);
-   uErr = QCBOREncode_GetErrorState(&EC);
-   if(uErr != QCBOR_ERR_TOO_MANY_CLOSES) {
-      return 4;
-   }
-
+   /* Try to extend byte string past end of encoding output buffer */
    QCBOREncode_Init(&EC, TestBuf);
    QCBOREncode_AddSZString(&EC, "012345678901234567");
    QCBOREncode_OpenBytes(&EC, &Place);
    /* Don't bother to write any bytes*/
    QCBOREncode_CloseBytes(&EC, Place.len+1);
    uErr = QCBOREncode_GetErrorState(&EC);
-   // TODO: sort out this error -- issues with UOB internal error state
    if(uErr != QCBOR_ERR_BUFFER_TOO_SMALL) {
-       return 5;
+      return 4;
    }
 
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   /* Close a byte string without opening one. */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_AddSZString(&EC, "012345678");
+   QCBOREncode_CloseBytes(&EC, 1);
+   uErr = QCBOREncode_GetErrorState(&EC);
+   if(uErr != QCBOR_ERR_TOO_MANY_CLOSES) {
+      return 5;
+   }
+
+   /* Forget to close a byte string */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_AddSZString(&EC, "012345678");
+   QCBOREncode_OpenBytes(&EC, &Place);
+   uErr = QCBOREncode_Finish(&EC, &Encoded);
+   if(uErr != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+      return 6;
+   }
+
+   /* Try to open a byte string in a byte string */
+   QCBOREncode_Init(&EC, TestBuf);
+   QCBOREncode_AddSZString(&EC, "012345678");
+   QCBOREncode_OpenBytes(&EC, &Place);
+   QCBOREncode_OpenBytes(&EC, &Place);
+   uErr = QCBOREncode_GetErrorState(&EC);
+   if(uErr != QCBOR_ERR_OPEN_BYTE_STRING) {
+      return 7;
+   }
+#endif  /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+   /* A successful case with a little complexity */
+   QCBOREncode_Init(&EC, TestBuf2);
+   QCBOREncode_OpenMap(&EC);
+      QCBOREncode_AddInt64ToMapN(&EC, 10, 22);
+      QCBOREncode_OpenBytesInMapN(&EC, 20, &Place);
+         Place.len = 2;
+         UsefulBuf_Set(Place, 'x');
+      QCBOREncode_CloseBytes(&EC, 2);
+      QCBOREncode_OpenBytesInMapSZ(&EC, "thirty", &Place);
+         Place.len = 3;
+         UsefulBuf_Set(Place, 'y');
+      QCBOREncode_CloseBytes(&EC, 3);
+      QCBOREncode_OpenArrayInMapN(&EC, 40);
+         QCBOREncode_OpenBytes(&EC, &Place);
+         QCBOREncode_CloseBytes(&EC, 0);
+      QCBOREncode_CloseArray(&EC);
+   QCBOREncode_CloseMap(&EC);
+   uErr = QCBOREncode_Finish(&EC, &Encoded);
+   if(uErr != QCBOR_SUCCESS) {
+      return 8;
+   }
+   if(UsefulBuf_Compare(Encoded,
+                        UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedForOpenBytes2))) {
+      return 9;
+   }
 
    return 0;
 }