@@ -68,6 +68,7 @@ public class JsonReader : BsonReader
68
68
private readonly JsonBuffer _buffer ;
69
69
private readonly JsonReaderSettings _jsonReaderSettings ; // same value as in base class just declared as derived class
70
70
private JsonReaderContext _context ;
71
+ private Guid ? _currentGuid ; // only relevant when _currentValue is a BsonBinaryData instance
71
72
private JsonToken _currentToken ;
72
73
private BsonValue _currentValue ;
73
74
private JsonToken _pushedToken ;
@@ -300,15 +301,15 @@ public override BsonType ReadBsonType()
300
301
break ;
301
302
case "BinData" :
302
303
CurrentBsonType = BsonType . Binary ;
303
- _currentValue = ParseBinDataConstructor ( ) ;
304
+ ( _currentValue , _currentGuid ) = ParseBinDataConstructor ( ) ;
304
305
break ;
305
306
case "Date" :
306
307
CurrentBsonType = BsonType . String ;
307
308
_currentValue = ParseDateTimeConstructor ( false ) ; // withNew = false
308
309
break ;
309
310
case "HexData" :
310
311
CurrentBsonType = BsonType . Binary ;
311
- _currentValue = ParseHexDataConstructor ( ) ;
312
+ ( _currentValue , _currentGuid ) = ParseHexDataConstructor ( ) ;
312
313
break ;
313
314
case "ISODate" :
314
315
CurrentBsonType = BsonType . DateTime ;
@@ -356,10 +357,10 @@ public override BsonType ReadBsonType()
356
357
case "PYUUID" :
357
358
case "PYGUID" :
358
359
CurrentBsonType = BsonType . Binary ;
359
- _currentValue = ParseUUIDConstructor ( valueToken . Lexeme ) ;
360
+ ( _currentValue , _currentGuid ) = ParseUUIDConstructor ( valueToken . Lexeme ) ;
360
361
break ;
361
362
case "new" :
362
- CurrentBsonType = ParseNew ( out _currentValue ) ;
363
+ ( CurrentBsonType , _currentValue , _currentGuid ) = ParseNew ( ) ;
363
364
break ;
364
365
default :
365
366
noValueFound = true ;
@@ -539,6 +540,49 @@ public override void ReadEndDocument()
539
540
}
540
541
}
541
542
543
+ /// <inheritdoc/>
544
+ public override Guid ReadGuid ( )
545
+ {
546
+ if ( Disposed ) { ThrowObjectDisposedException ( ) ; }
547
+ VerifyBsonType ( nameof ( ReadGuid ) , BsonType . Binary ) ;
548
+ State = GetNextState ( ) ;
549
+
550
+ if ( _currentGuid . HasValue )
551
+ {
552
+ return _currentGuid . Value ;
553
+ }
554
+
555
+ var binaryData = _currentValue . AsBsonBinaryData ;
556
+ if ( binaryData . SubType != BsonBinarySubType . UuidStandard )
557
+ {
558
+ throw new FormatException ( $ "GuidRepresentation is unknown for binary subtype { binaryData . SubType } .") ;
559
+ }
560
+
561
+ return GuidConverter . FromBytes ( binaryData . Bytes , GuidRepresentation . Standard ) ;
562
+ }
563
+
564
+ /// <inheritdoc/>
565
+ public override Guid ReadGuid ( GuidRepresentation guidRepresentation )
566
+ {
567
+ if ( Disposed ) { ThrowObjectDisposedException ( ) ; }
568
+ VerifyBsonType ( nameof ( ReadGuid ) , BsonType . Binary ) ;
569
+ State = GetNextState ( ) ;
570
+
571
+ if ( _currentGuid . HasValue )
572
+ {
573
+ return _currentGuid . Value ;
574
+ }
575
+
576
+ var binaryData = _currentValue . AsBsonBinaryData ;
577
+ var expectedSubType = GuidConverter . GetSubType ( guidRepresentation ) ;
578
+ if ( binaryData . SubType != expectedSubType )
579
+ {
580
+ throw new FormatException ( $ "Expected the binary sub type to be { expectedSubType } , but it was { binaryData . SubType } ") ;
581
+ }
582
+
583
+ return GuidConverter . FromBytes ( binaryData . Bytes , guidRepresentation ) ;
584
+ }
585
+
542
586
/// <summary>
543
587
/// Reads a BSON Int32 from the reader.
544
588
/// </summary>
@@ -935,7 +979,7 @@ private bool IsValidBinaryDataSubTypeString(string value)
935
979
HexUtils . IsValidHexString ( value ) ;
936
980
}
937
981
938
- private BsonValue ParseBinDataConstructor ( )
982
+ private ( BsonBinaryData , Guid ? ) ParseBinDataConstructor ( )
939
983
{
940
984
VerifyToken ( "(" ) ;
941
985
var subTypeToken = PopToken ( ) ;
@@ -954,10 +998,10 @@ private BsonValue ParseBinDataConstructor()
954
998
VerifyToken ( ")" ) ;
955
999
var bytes = Convert . FromBase64String ( bytesToken . StringValue ) ;
956
1000
var subType = ( BsonBinarySubType ) subTypeToken . Int32Value ;
957
- return new BsonBinaryData ( bytes , subType ) ;
1001
+ return ( new BsonBinaryData ( bytes , subType ) , null ) ;
958
1002
}
959
1003
960
- private BsonValue ParseBinDataExtendedJson ( )
1004
+ private ( BsonBinaryData , Guid ? ) ParseBinDataExtendedJson ( )
961
1005
{
962
1006
VerifyToken ( ":" ) ;
963
1007
@@ -976,7 +1020,7 @@ private BsonValue ParseBinDataExtendedJson()
976
1020
977
1021
VerifyToken ( "}" ) ;
978
1022
979
- return new BsonBinaryData ( bytes , subType ) ;
1023
+ return ( new BsonBinaryData ( bytes , subType ) , null ) ;
980
1024
}
981
1025
982
1026
private void ParseBinDataExtendedJsonCanonical ( out byte [ ] bytes , out BsonBinarySubType subType )
@@ -1080,7 +1124,7 @@ private void ParseBinDataExtendedJsonLegacy(JsonToken nextToken, out byte[] byte
1080
1124
}
1081
1125
}
1082
1126
1083
- private BsonValue ParseHexDataConstructor ( )
1127
+ private ( BsonBinaryData , Guid ? ) ParseHexDataConstructor ( )
1084
1128
{
1085
1129
VerifyToken ( "(" ) ;
1086
1130
var subTypeToken = PopToken ( ) ;
@@ -1100,7 +1144,13 @@ private BsonValue ParseHexDataConstructor()
1100
1144
var bytes = BsonUtils . ParseHexString ( bytesToken . StringValue ) ;
1101
1145
var subType = ( BsonBinarySubType ) subTypeToken . Int32Value ;
1102
1146
1103
- return new BsonBinaryData ( bytes , subType ) ;
1147
+ if ( ( subType == BsonBinarySubType . UuidStandard || subType == BsonBinarySubType . UuidLegacy ) &&
1148
+ bytes . Length != 16 )
1149
+ {
1150
+ throw new FormatException ( $ "Length must be 16, not { bytes . Length } , when subType is { subType } .") ;
1151
+ }
1152
+
1153
+ return ( new BsonBinaryData ( bytes , subType ) , null ) ;
1104
1154
}
1105
1155
1106
1156
private BsonType ParseJavaScriptExtendedJson ( out BsonValue value )
@@ -1291,7 +1341,7 @@ private BsonType ParseExtendedJson()
1291
1341
{
1292
1342
switch ( nameToken . StringValue )
1293
1343
{
1294
- case "$binary" : _currentValue = ParseBinDataExtendedJson ( ) ; return BsonType . Binary ;
1344
+ case "$binary" : ( _currentValue , _currentGuid ) = ParseBinDataExtendedJson ( ) ; return BsonType . Binary ;
1295
1345
case "$code" : return ParseJavaScriptExtendedJson ( out _currentValue ) ;
1296
1346
case "$date" : _currentValue = ParseDateTimeExtendedJson ( ) ; return BsonType . DateTime ;
1297
1347
case "$maxkey" : case "$maxKey" : _currentValue = ParseMaxKeyExtendedJson ( ) ; return BsonType . MaxKey ;
@@ -1311,7 +1361,7 @@ private BsonType ParseExtendedJson()
1311
1361
case "$symbol" : _currentValue = ParseSymbolExtendedJson ( ) ; return BsonType . Symbol ;
1312
1362
case "$timestamp" : _currentValue = ParseTimestampExtendedJson ( ) ; return BsonType . Timestamp ;
1313
1363
case "$undefined" : _currentValue = ParseUndefinedExtendedJson ( ) ; return BsonType . Undefined ;
1314
- case "$uuid" : _currentValue = ParseUuidExtendedJson ( ) ; return BsonType . Binary ;
1364
+ case "$uuid" : ( _currentValue , _currentGuid ) = ParseUuidExtendedJson ( ) ; return BsonType . Binary ;
1315
1365
}
1316
1366
}
1317
1367
ReturnToBookmark ( bookmark ) ;
@@ -1491,46 +1541,49 @@ private BsonValue ParseMinKeyExtendedJson()
1491
1541
return BsonMinKey . Value ;
1492
1542
}
1493
1543
1494
- private BsonType ParseNew ( out BsonValue value )
1544
+ private ( BsonType , BsonValue , Guid ? ) ParseNew ( )
1495
1545
{
1496
1546
var typeToken = PopToken ( ) ;
1497
1547
if ( typeToken . Type != JsonTokenType . UnquotedString )
1498
1548
{
1499
1549
var message = string . Format ( "JSON reader expected a type name but found '{0}'." , typeToken . Lexeme ) ;
1500
1550
throw new FormatException ( message ) ;
1501
1551
}
1552
+
1553
+ BsonValue value ;
1554
+ Guid ? guid = null ;
1502
1555
switch ( typeToken . Lexeme )
1503
1556
{
1504
1557
case "BinData" :
1505
- value = ParseBinDataConstructor ( ) ;
1506
- return BsonType . Binary ;
1558
+ ( value , guid ) = ParseBinDataConstructor ( ) ;
1559
+ return ( BsonType . Binary , value , guid ) ;
1507
1560
case "Date" :
1508
1561
value = ParseDateTimeConstructor ( true ) ; // withNew = true
1509
- return BsonType . DateTime ;
1562
+ return ( BsonType . DateTime , value , null ) ;
1510
1563
case "HexData" :
1511
- value = ParseHexDataConstructor ( ) ;
1512
- return BsonType . Binary ;
1564
+ ( value , guid ) = ParseHexDataConstructor ( ) ;
1565
+ return ( BsonType . Binary , value , guid ) ;
1513
1566
case "ISODate" :
1514
1567
value = ParseISODateTimeConstructor ( ) ;
1515
- return BsonType . DateTime ;
1568
+ return ( BsonType . DateTime , value , null ) ;
1516
1569
case "NumberDecimal" :
1517
1570
value = ParseNumberDecimalConstructor ( ) ;
1518
- return BsonType . Decimal128 ;
1571
+ return ( BsonType . Decimal128 , value , null ) ;
1519
1572
case "NumberInt" :
1520
1573
value = ParseNumberConstructor ( ) ;
1521
- return BsonType . Int32 ;
1574
+ return ( BsonType . Int32 , value , null ) ;
1522
1575
case "NumberLong" :
1523
1576
value = ParseNumberLongConstructor ( ) ;
1524
- return BsonType . Int64 ;
1577
+ return ( BsonType . Int64 , value , null ) ;
1525
1578
case "ObjectId" :
1526
1579
value = ParseObjectIdConstructor ( ) ;
1527
- return BsonType . ObjectId ;
1580
+ return ( BsonType . ObjectId , value , null ) ;
1528
1581
case "RegExp" :
1529
1582
value = ParseRegularExpressionConstructor ( ) ;
1530
- return BsonType . RegularExpression ;
1583
+ return ( BsonType . RegularExpression , value , null ) ;
1531
1584
case "Timestamp" :
1532
1585
value = ParseTimestampConstructor ( ) ;
1533
- return BsonType . Timestamp ;
1586
+ return ( BsonType . Timestamp , value , null ) ;
1534
1587
case "UUID" :
1535
1588
case "GUID" :
1536
1589
case "CSUUID" :
@@ -1539,8 +1592,8 @@ private BsonType ParseNew(out BsonValue value)
1539
1592
case "JGUID" :
1540
1593
case "PYUUID" :
1541
1594
case "PYGUID" :
1542
- value = ParseUUIDConstructor ( typeToken . Lexeme ) ;
1543
- return BsonType . Binary ;
1595
+ ( value , guid ) = ParseUUIDConstructor ( typeToken . Lexeme ) ;
1596
+ return ( BsonType . Binary , value , guid ) ;
1544
1597
default :
1545
1598
var message = string . Format ( "JSON reader expected a type name but found '{0}'." , typeToken . Lexeme ) ;
1546
1599
throw new FormatException ( message ) ;
@@ -2036,7 +2089,7 @@ private BsonValue ParseUndefinedExtendedJson()
2036
2089
return BsonMaxKey . Value ;
2037
2090
}
2038
2091
2039
- private BsonValue ParseUuidExtendedJson ( )
2092
+ private ( BsonBinaryData , Guid ? ) ParseUuidExtendedJson ( )
2040
2093
{
2041
2094
VerifyToken ( ":" ) ;
2042
2095
var uuidToken = PopToken ( ) ;
@@ -2048,10 +2101,12 @@ private BsonValue ParseUuidExtendedJson()
2048
2101
VerifyToken ( "}" ) ;
2049
2102
2050
2103
var guid = Guid . Parse ( uuidToken . StringValue ) ;
2051
- return new BsonBinaryData ( guid , GuidRepresentation . Standard ) ;
2104
+ var bytes = GuidConverter . ToBytes ( guid , GuidRepresentation . Standard ) ;
2105
+
2106
+ return ( new BsonBinaryData ( bytes , BsonBinarySubType . UuidStandard ) , guid ) ;
2052
2107
}
2053
2108
2054
- private BsonValue ParseUUIDConstructor ( string uuidConstructorName )
2109
+ private ( BsonBinaryData , Guid ? ) ParseUUIDConstructor ( string uuidConstructorName )
2055
2110
{
2056
2111
VerifyToken ( "(" ) ;
2057
2112
var bytesToken = PopToken ( ) ;
@@ -2089,7 +2144,7 @@ private BsonValue ParseUUIDConstructor(string uuidConstructorName)
2089
2144
bytes = GuidConverter . ToBytes ( guid , guidRepresentation ) ;
2090
2145
var subType = GuidConverter . GetSubType ( guidRepresentation ) ;
2091
2146
2092
- return new BsonBinaryData ( bytes , subType ) ;
2147
+ return ( new BsonBinaryData ( bytes , subType ) , guid ) ;
2093
2148
}
2094
2149
2095
2150
private JsonToken PopToken ( )
0 commit comments