Newer
Older
static basic_json from_msgpack_internal(const std::vector<uint8_t> &v,
size_t &idx)
{
// make sure reading 1 byte is safe
check_length(v.size(), 1, idx);
// store and increment index
const size_t current_idx = idx++;
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
if (v[current_idx] <= 0x7f) // positive fixint
{
return v[current_idx];
}
if (v[current_idx] <= 0x8f) // fixmap
{
basic_json result = value_t::object;
const size_t len = v[current_idx] & 0x0f;
for (size_t i = 0; i < len; ++i)
{
std::string key = from_msgpack_internal(v, idx);
result[key] = from_msgpack_internal(v, idx);
}
return result;
}
else if (v[current_idx] <= 0x9f) // fixarray
{
basic_json result = value_t::array;
const size_t len = v[current_idx] & 0x0f;
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_msgpack_internal(v, idx));
}
return result;
}
else // fixstr
{
const size_t len = v[current_idx] & 0x1f;
const size_t offset = current_idx + 1;
idx += len; // skip content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
else if (v[current_idx] >= 0xe0) // negative fixint
return static_cast<int8_t>(v[current_idx]);
else
{
switch (v[current_idx])
{
case 0xc0: // nil
{
return value_t::null;
}
case 0xc2: // false
{
return false;
}
case 0xc3: // true
{
return true;
}
case 0xca: // float 32
{
// copy bytes in reverse order into the double variable
float res;
for (size_t byte = 0; byte < sizeof(float); ++byte)
{
reinterpret_cast<uint8_t *>(&res)[sizeof(float) - byte - 1] =
v.at(current_idx + 1 + byte);
}
idx += sizeof(float); // skip content bytes
return res;
}
case 0xcb: // float 64
{
// copy bytes in reverse order into the double variable
double res;
for (size_t byte = 0; byte < sizeof(double); ++byte)
{
reinterpret_cast<uint8_t *>(&res)[sizeof(double) - byte - 1] =
v.at(current_idx + 1 + byte);
}
idx += sizeof(double); // skip content bytes
return res;
}
case 0xcc: // uint 8
{
idx += 1; // skip content byte
return get_from_vector<uint8_t>(v, current_idx);
}
case 0xcd: // uint 16
{
idx += 2; // skip 2 content bytes
return get_from_vector<uint16_t>(v, current_idx);
}
case 0xce: // uint 32
{
idx += 4; // skip 4 content bytes
return get_from_vector<uint32_t>(v, current_idx);
}
case 0xcf: // uint 64
{
idx += 8; // skip 8 content bytes
return get_from_vector<uint64_t>(v, current_idx);
}
case 0xd0: // int 8
{
idx += 1; // skip content byte
return get_from_vector<int8_t>(v, current_idx);
}
case 0xd1: // int 16
{
idx += 2; // skip 2 content bytes
return get_from_vector<int16_t>(v, current_idx);
}
case 0xd2: // int 32
{
idx += 4; // skip 4 content bytes
return get_from_vector<int32_t>(v, current_idx);
}
case 0xd3: // int 64
{
idx += 8; // skip 8 content bytes
return get_from_vector<int64_t>(v, current_idx);
}
case 0xd9: // str 8
{
const auto len =
static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
const size_t offset = current_idx + 2;
idx += len + 1; // skip size byte + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0xda: // str 16
{
const auto len =
static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
const size_t offset = current_idx + 3;
idx += len + 2; // skip 2 size bytes + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0xdb: // str 32
{
const auto len =
static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
const size_t offset = current_idx + 5;
idx += len + 4; // skip 4 size bytes + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0xdc: // array 16
{
basic_json result = value_t::array;
const auto len =
static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
idx += 2; // skip 2 size bytes
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_msgpack_internal(v, idx));
}
return result;
}
case 0xdd: // array 32
{
basic_json result = value_t::array;
const auto len =
static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
idx += 4; // skip 4 size bytes
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_msgpack_internal(v, idx));
}
return result;
}
case 0xde: // map 16
{
basic_json result = value_t::object;
const auto len =
static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
idx += 2; // skip 2 size bytes
for (size_t i = 0; i < len; ++i)
{
std::string key = from_msgpack_internal(v, idx);
result[key] = from_msgpack_internal(v, idx);
}
return result;
}
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
case 0xdf: // map 32
{
basic_json result = value_t::object;
const auto len =
static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
idx += 4; // skip 4 size bytes
for (size_t i = 0; i < len; ++i)
{
std::string key = from_msgpack_internal(v, idx);
result[key] = from_msgpack_internal(v, idx);
}
return result;
}
default:
{
JSON_THROW(std::invalid_argument(
"error parsing a msgpack @ " + std::to_string(current_idx) +
": " + std::to_string(static_cast<int>(v[current_idx]))));
}
}
}
}
/*!
@brief create a JSON value from a given CBOR vector
@param[in] v CBOR serialization
@param[in] idx byte index to start reading from @a v
@return deserialized JSON value
@throw std::invalid_argument if unsupported features from CBOR were used in
the given vector @a v or if the input is not valid CBOR
@throw std::out_of_range if the given vector ends prematurely
@sa https://tools.ietf.org/html/rfc7049
*/
static basic_json from_cbor_internal(const std::vector<uint8_t> &v,
size_t &idx)
{
// store and increment index
const size_t current_idx = idx++;
switch (v.at(current_idx))
{
// Integer 0x00..0x17 (0..23)
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
{
return v[current_idx];
}
case 0x18: // Unsigned integer (one-byte uint8_t follows)
{
idx += 1; // skip content byte
return get_from_vector<uint8_t>(v, current_idx);
}
case 0x19: // Unsigned integer (two-byte uint16_t follows)
{
idx += 2; // skip 2 content bytes
return get_from_vector<uint16_t>(v, current_idx);
}
case 0x1a: // Unsigned integer (four-byte uint32_t follows)
{
idx += 4; // skip 4 content bytes
return get_from_vector<uint32_t>(v, current_idx);
}
case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
{
idx += 8; // skip 8 content bytes
return get_from_vector<uint64_t>(v, current_idx);
}
// Negative integer -1-0x00..-1-0x17 (-1..-24)
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
{
return static_cast<int8_t>(0x20 - 1 - v[current_idx]);
}
case 0x38: // Negative integer (one-byte uint8_t follows)
{
idx += 1; // skip content byte
// must be uint8_t !
return static_cast<number_integer_t>(-1) -
get_from_vector<uint8_t>(v, current_idx);
}
case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
{
idx += 2; // skip 2 content bytes
return static_cast<number_integer_t>(-1) -
get_from_vector<uint16_t>(v, current_idx);
}
case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
{
idx += 4; // skip 4 content bytes
return static_cast<number_integer_t>(-1) -
get_from_vector<uint32_t>(v, current_idx);
}
case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
{
idx += 8; // skip 8 content bytes
return static_cast<number_integer_t>(-1) -
static_cast<number_integer_t>(
get_from_vector<uint64_t>(v, current_idx));
}
// UTF-8 string (0x00..0x17 bytes follow)
case 0x60:
case 0x61:
case 0x62:
case 0x63:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
case 0x68:
case 0x69:
case 0x6a:
case 0x6b:
case 0x6c:
case 0x6d:
case 0x6e:
case 0x6f:
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
{
const auto len = static_cast<size_t>(v[current_idx] - 0x60);
const size_t offset = current_idx + 1;
idx += len; // skip content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
{
const auto len =
static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
const size_t offset = current_idx + 2;
idx += len + 1; // skip size byte + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
{
const auto len =
static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
const size_t offset = current_idx + 3;
idx += len + 2; // skip 2 size bytes + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
{
const auto len =
static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
const size_t offset = current_idx + 5;
idx += len + 4; // skip 4 size bytes + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
{
const auto len =
static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
const size_t offset = current_idx + 9;
idx += len + 8; // skip 8 size bytes + content bytes
check_length(v.size(), len, offset);
return std::string(reinterpret_cast<const char *>(v.data()) + offset,
len);
}
case 0x7f: // UTF-8 string (indefinite length)
{
std::string result;
while (v.at(idx) != 0xff)
{
string_t s = from_cbor_internal(v, idx);
result += s;
}
// skip break byte (0xFF)
idx += 1;
return result;
}
// array (0x00..0x17 data items follow)
case 0x80:
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
case 0x88:
case 0x89:
case 0x8a:
case 0x8b:
case 0x8c:
case 0x8d:
case 0x8e:
case 0x8f:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97:
{
basic_json result = value_t::array;
const auto len = static_cast<size_t>(v[current_idx] - 0x80);
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_cbor_internal(v, idx));
}
return result;
}
case 0x98: // array (one-byte uint8_t for n follows)
{
basic_json result = value_t::array;
const auto len =
static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
idx += 1; // skip 1 size byte
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_cbor_internal(v, idx));
}
return result;
}
case 0x99: // array (two-byte uint16_t for n follow)
{
basic_json result = value_t::array;
const auto len =
static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
idx += 2; // skip 4 size bytes
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_cbor_internal(v, idx));
}
return result;
}
case 0x9a: // array (four-byte uint32_t for n follow)
{
basic_json result = value_t::array;
const auto len =
static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
idx += 4; // skip 4 size bytes
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_cbor_internal(v, idx));
}
return result;
}
case 0x9b: // array (eight-byte uint64_t for n follow)
{
basic_json result = value_t::array;
const auto len =
static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
idx += 8; // skip 8 size bytes
for (size_t i = 0; i < len; ++i)
{
result.push_back(from_cbor_internal(v, idx));
}
return result;
}
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
case 0x9f: // array (indefinite length)
{
basic_json result = value_t::array;
while (v.at(idx) != 0xff)
{
result.push_back(from_cbor_internal(v, idx));
}
// skip break byte (0xFF)
idx += 1;
return result;
}
// map (0x00..0x17 pairs of data items follow)
case 0xa0:
case 0xa1:
case 0xa2:
case 0xa3:
case 0xa4:
case 0xa5:
case 0xa6:
case 0xa7:
case 0xa8:
case 0xa9:
case 0xaa:
case 0xab:
case 0xac:
case 0xad:
case 0xae:
case 0xaf:
case 0xb0:
case 0xb1:
case 0xb2:
case 0xb3:
case 0xb4:
case 0xb5:
case 0xb6:
case 0xb7:
{
basic_json result = value_t::object;
const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
for (size_t i = 0; i < len; ++i)
{
std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx);
}
return result;
}
case 0xb8: // map (one-byte uint8_t for n follows)
{
basic_json result = value_t::object;
const auto len =
static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
idx += 1; // skip 1 size byte
for (size_t i = 0; i < len; ++i)
{
std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx);
}
return result;
}
case 0xb9: // map (two-byte uint16_t for n follow)
{
basic_json result = value_t::object;
const auto len =
static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
idx += 2; // skip 2 size bytes
for (size_t i = 0; i < len; ++i)
{
std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx);
}
return result;
}
case 0xba: // map (four-byte uint32_t for n follow)
{
basic_json result = value_t::object;
const auto len =
static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
idx += 4; // skip 4 size bytes
for (size_t i = 0; i < len; ++i)
{
std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx);
}
return result;
}
case 0xbb: // map (eight-byte uint64_t for n follow)
{
basic_json result = value_t::object;
const auto len =
static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
idx += 8; // skip 8 size bytes
for (size_t i = 0; i < len; ++i)
{
std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx);
}
return result;
}
case 0xbf: // map (indefinite length)
{
basic_json result = value_t::object;
while (v.at(idx) != 0xff)
{
std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx);
}
// skip break byte (0xFF)
idx += 1;
return result;
}
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
case 0xf4: // false
{
return false;
}
case 0xf5: // true
{
return true;
}
case 0xf6: // null
{
return value_t::null;
}
case 0xf9: // Half-Precision Float (two-byte IEEE 754)
{
idx += 2; // skip two content bytes
// code from RFC 7049, Appendix D, Figure 3:
// As half-precision floating-point numbers were only added to
// IEEE 754 in 2008, today's programming platforms often still
// only have limited support for them. It is very easy to
// include at least decoding support for them even without such
// support. An example of a small decoder for half-precision
// floating-point numbers in the C language is shown in Fig. 3.
const int half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2);
const int exp = (half >> 10) & 0x1f;
const int mant = half & 0x3ff;
double val;
if (exp == 0)
{
val = std::ldexp(mant, -24);
}
else if (exp != 31)
{
val = std::ldexp(mant + 1024, exp - 25);
}
else
{
val = mant == 0 ? INFINITY : NAN;
}
return (half & 0x8000) != 0 ? -val : val;
}
case 0xfa: // Single-Precision Float (four-byte IEEE 754)
{
// copy bytes in reverse order into the float variable
float res;
for (size_t byte = 0; byte < sizeof(float); ++byte)
{
reinterpret_cast<uint8_t *>(&res)[sizeof(float) - byte - 1] =
v.at(current_idx + 1 + byte);
}
idx += sizeof(float); // skip content bytes
return res;
}
case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
{
// copy bytes in reverse order into the double variable
double res;
for (size_t byte = 0; byte < sizeof(double); ++byte)
{
reinterpret_cast<uint8_t *>(&res)[sizeof(double) - byte - 1] =
v.at(current_idx + 1 + byte);
}
idx += sizeof(double); // skip content bytes
return res;
}
default: // anything else (0xFF is handled inside the other types)
{
JSON_THROW(std::invalid_argument(
"error parsing a CBOR @ " + std::to_string(current_idx) + ": " +
std::to_string(static_cast<int>(v[current_idx]))));
}
public:
/*!
@brief create a MessagePack serialization of a given JSON value
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
Serializes a given JSON value @a j to a byte vector using the MessagePack
serialization format. MessagePack is a binary serialization format which
aims to be more compact than JSON itself, yet more efficient to parse.
@param[in] j JSON value to serialize
@return MessagePack serialization as byte vector
@complexity Linear in the size of the JSON value @a j.
@liveexample{The example shows the serialization of a JSON value to a byte
vector in MessagePack format.,to_msgpack}
@sa http://msgpack.org
@sa @ref from_msgpack(const std::vector<uint8_t>&) for the analogous
deserialization
@sa @ref to_cbor(const basic_json& for the related CBOR format
*/
static std::vector<uint8_t> to_msgpack(const basic_json &j)
{
std::vector<uint8_t> result;
to_msgpack_internal(j, result);
return result;
}
/*!
@brief create a JSON value from a byte vector in MessagePack format
Deserializes a given byte vector @a v to a JSON value using the MessagePack
serialization format.
@param[in] v a byte vector in MessagePack format
@return deserialized JSON value
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
7852
7853
7854
7855
7856
7857
7858
7859
7860
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
@throw std::invalid_argument if unsupported features from MessagePack were
used in the given vector @a v or if the input is not valid MessagePack
@throw std::out_of_range if the given vector ends prematurely
@complexity Linear in the size of the byte vector @a v.
@liveexample{The example shows the deserialization of a byte vector in
MessagePack format to a JSON value.,from_msgpack}
@sa http://msgpack.org
@sa @ref to_msgpack(const basic_json&) for the analogous serialization
@sa @ref from_cbor(const std::vector<uint8_t>&) for the related CBOR format
*/
static basic_json from_msgpack(const std::vector<uint8_t> &v)
{
size_t i = 0;
return from_msgpack_internal(v, i);
}
/*!
@brief create a MessagePack serialization of a given JSON value
Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
Binary Object Representation) serialization format. CBOR is a binary
serialization format which aims to be more compact than JSON itself, yet
more efficient to parse.
@param[in] j JSON value to serialize
@return MessagePack serialization as byte vector
@complexity Linear in the size of the JSON value @a j.
@liveexample{The example shows the serialization of a JSON value to a byte
vector in CBOR format.,to_cbor}
@sa http://cbor.io
@sa @ref from_cbor(const std::vector<uint8_t>&) for the analogous
deserialization
@sa @ref to_msgpack(const basic_json& for the related MessagePack format
*/
static std::vector<uint8_t> to_cbor(const basic_json &j)
{
std::vector<uint8_t> result;
to_cbor_internal(j, result);
return result;
}
/*!
@brief create a JSON value from a byte vector in CBOR format
Deserializes a given byte vector @a v to a JSON value using the CBOR
(Concise Binary Object Representation) serialization format.
@param[in] v a byte vector in CBOR format
@return deserialized JSON value
@throw std::invalid_argument if unsupported features from CBOR were used in
the given vector @a v or if the input is not valid MessagePack
@throw std::out_of_range if the given vector ends prematurely
@complexity Linear in the size of the byte vector @a v.
@liveexample{The example shows the deserialization of a byte vector in CBOR
format to a JSON value.,from_cbor}
@sa http://cbor.io
@sa @ref to_cbor(const basic_json&) for the analogous serialization
@sa @ref from_msgpack(const std::vector<uint8_t>&) for the related
MessagePack format
*/
static basic_json from_cbor(const std::vector<uint8_t> &v)
{
size_t i = 0;
return from_cbor_internal(v, i);
}
/// @}
private:
///////////////////////////
// convenience functions //
///////////////////////////
/*!
@brief return the type as string
Returns the type name as string to be used in error messages - usually to
indicate that a function was called on a wrong JSON type.
@return basically a string representation of a the @a m_type member
@complexity Constant.
@since version 1.0.0
*/
std::string type_name() const
{
switch (m_type)
{
case value_t::null:
return "null";
case value_t::object:
return "object";
case value_t::array:
return "array";
case value_t::string:
return "string";
case value_t::boolean:
return "boolean";
case value_t::discarded:
return "discarded";
default:
return "number";
}
}
/*!
@brief calculates the extra space to escape a JSON string
@param[in] s the string to escape
@return the number of characters required to escape string @a s
@complexity Linear in the length of string @a s.
*/
static std::size_t extra_space(const string_t &s) noexcept
{
return std::accumulate(s.begin(), s.end(), size_t{},
[](size_t res, typename string_t::value_type c) {
switch (c)
{
case '"':
case '\\':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
{
// from c (1 byte) to \x (2 bytes)
return res + 1;
}
default:
{
if (c >= 0x00 and c <= 0x1f)
{
// from c (1 byte) to \uxxxx (6 bytes)
return res + 5;
}
return res;
}
}
});
}
Escape a string by replacing certain special characters by a sequence of
an escape character (backslash) and another character and other control
characters by a sequence of "\u" followed by a four-digit hex
representation.
@param[in] s the string to escape
@return the escaped string
@complexity Linear in the length of string @a s.
*/
static string_t escape_string(const string_t &s)
{
const auto space = extra_space(s);
if (space == 0)
{
return s;
}
// create a result string of necessary size
string_t result(s.size() + space, '\\');
std::size_t pos = 0;
for (const auto &c : s)
switch (c)
{
// quotation mark (0x22)
case '"':
result[pos + 1] = '"';
pos += 2;
break;
}
// reverse solidus (0x5c)
case '\\':
{
// nothing to change
pos += 2;
break;
}
// backspace (0x08)
case '\b':
{
result[pos + 1] = 'b';
pos += 2;
break;