From df33a90774c8a63140b49685c47be964a2409167 Mon Sep 17 00:00:00 2001
From: Julian Becker <becker.julian@gmail.com>
Date: Sat, 15 Sep 2018 14:08:38 +0200
Subject: [PATCH] BSON: Bugfix for non-empty arrays

---
 .../nlohmann/detail/input/binary_reader.hpp   | 37 +++++--------------
 single_include/nlohmann/json.hpp              | 37 +++++--------------
 test/src/unit-bson.cpp                        | 35 ++++++++++++++++++
 3 files changed, 55 insertions(+), 54 deletions(-)

diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp
index 140cd8ab..f4049bd3 100644
--- a/include/nlohmann/detail/input/binary_reader.hpp
+++ b/include/nlohmann/detail/input/binary_reader.hpp
@@ -157,17 +157,21 @@ class binary_reader
         return success;
     }
 
-    void parse_bson_entries()
+    void parse_bson_entries(bool is_array)
     {
         while (auto entry_type = get())
         {
+            string_t key;
+            get_bson_cstr(key);
+            if (!is_array)
+            {
+                sax->key(key);
+            }
+
             switch (entry_type)
             {
                 case 0x01: // double
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     double number;
                     get_number_little_endian(number);
                     sax->number_float(static_cast<number_float_t>(number), "");
@@ -175,9 +179,6 @@ class binary_reader
                 break;
                 case 0x02: // string
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     std::int32_t len;
                     string_t value;
                     get_number_little_endian(len);
@@ -188,17 +189,11 @@ class binary_reader
                 break;
                 case 0x08: // boolean
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     sax->boolean(static_cast<bool>(get()));
                 }
                 break;
                 case 0x10: // int32
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     std::int32_t value;
                     get_number_little_endian(value);
                     sax->number_integer(static_cast<std::int32_t>(value));
@@ -206,9 +201,6 @@ class binary_reader
                 break;
                 case 0x12: // int64
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     std::int64_t value;
                     get_number_little_endian(value);
                     sax->number_integer(static_cast<std::int64_t>(value));
@@ -216,25 +208,16 @@ class binary_reader
                 break;
                 case 0x0A: // null
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     sax->null();
                 }
                 break;
                 case 0x03: // object
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     parse_bson_internal();
                 }
                 break;
                 case 0x04: // array
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     parse_bson_array();
                 }
                 break;
@@ -252,7 +235,7 @@ class binary_reader
             return false;
         }
 
-        parse_bson_entries();
+        parse_bson_entries(/*is_array*/true);
 
         const auto result = sax->end_array();
 
@@ -269,7 +252,7 @@ class binary_reader
             return false;
         }
 
-        parse_bson_entries();
+        parse_bson_entries(/*is_array*/false);
 
         const auto result = sax->end_object();
 
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index adb0d294..6f481a8f 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -6141,17 +6141,21 @@ class binary_reader
         return success;
     }
 
-    void parse_bson_entries()
+    void parse_bson_entries(bool is_array)
     {
         while (auto entry_type = get())
         {
+            string_t key;
+            get_bson_cstr(key);
+            if (!is_array)
+            {
+                sax->key(key);
+            }
+
             switch (entry_type)
             {
                 case 0x01: // double
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     double number;
                     get_number_little_endian(number);
                     sax->number_float(static_cast<number_float_t>(number), "");
@@ -6159,9 +6163,6 @@ class binary_reader
                 break;
                 case 0x02: // string
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     std::int32_t len;
                     string_t value;
                     get_number_little_endian(len);
@@ -6172,17 +6173,11 @@ class binary_reader
                 break;
                 case 0x08: // boolean
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     sax->boolean(static_cast<bool>(get()));
                 }
                 break;
                 case 0x10: // int32
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     std::int32_t value;
                     get_number_little_endian(value);
                     sax->number_integer(static_cast<std::int32_t>(value));
@@ -6190,9 +6185,6 @@ class binary_reader
                 break;
                 case 0x12: // int64
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     std::int64_t value;
                     get_number_little_endian(value);
                     sax->number_integer(static_cast<std::int64_t>(value));
@@ -6200,25 +6192,16 @@ class binary_reader
                 break;
                 case 0x0A: // null
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     sax->null();
                 }
                 break;
                 case 0x03: // object
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     parse_bson_internal();
                 }
                 break;
                 case 0x04: // array
                 {
-                    string_t key;
-                    get_bson_cstr(key);
-                    sax->key(key);
                     parse_bson_array();
                 }
                 break;
@@ -6236,7 +6219,7 @@ class binary_reader
             return false;
         }
 
-        parse_bson_entries();
+        parse_bson_entries(/*is_array*/true);
 
         const auto result = sax->end_array();
 
@@ -6253,7 +6236,7 @@ class binary_reader
             return false;
         }
 
-        parse_bson_entries();
+        parse_bson_entries(/*is_array*/false);
 
         const auto result = sax->end_object();
 
diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp
index b2886110..fcaf51d6 100644
--- a/test/src/unit-bson.cpp
+++ b/test/src/unit-bson.cpp
@@ -408,6 +408,41 @@ TEST_CASE("BSON")
             CHECK(json::from_bson(result, true, false) == j);
         }
 
+        SECTION("non-empty object with non-empty array member")
+        {
+            json j =
+            {
+                { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) }
+            };
+
+            std::vector<uint8_t> expected =
+            {
+                0x41, 0x00, 0x00, 0x00, // size (little endian)
+                0x04, /// entry: embedded document
+                'e', 'n', 't', 'r', 'y', '\x00',
+
+                0x35, 0x00, 0x00, 0x00, // size (little endian)
+                0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x02, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x03, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x05, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x06, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x07, 0x00, 0x00, 0x00,
+                0x10, 0x00, 0x08, 0x00, 0x00, 0x00,
+                0x00, // end marker (embedded document)
+
+                0x00 // end marker
+            };
+
+            const auto result = json::to_bson(j);
+            CHECK(result == expected);
+
+            // roundtrip
+            CHECK(json::from_bson(result) == j);
+            CHECK(json::from_bson(result, true, false) == j);
+        }
+
         SECTION("Some more complex document")
         {
             // directly encoding uint64 is not supported in bson (only for timestamp values)