Skip to content

Commit 559a6bf

Browse files
committed
V3.4.0
1 parent 85e82b6 commit 559a6bf

File tree

15 files changed

+83
-44
lines changed

15 files changed

+83
-44
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 3.4.0
22

33
- Stellar Address Support: Add support for stellar Contract address.
4+
- Fix incorrect CBOR encoding of large negative integers.
45

56
## 3.3.0
67

lib/cbor/cbor.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ library cbor;
55
export 'core/cbor.dart';
66

77
export 'types/types.dart';
8+
9+
export 'exception/exception.dart';

lib/cbor/core/cbor.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import 'package:blockchain_utils/cbor/exception/exception.dart';
12
import 'package:blockchain_utils/utils/utils.dart';
23
import 'package:blockchain_utils/cbor/types/types.dart';
34
import 'package:blockchain_utils/cbor/utils/cbor_utils.dart';
4-
import 'package:blockchain_utils/exception/exception.dart';
55

66
/// An abstract class representing a CBOR (Concise Binary Object Representation) object.
77
/// CBOR objects can hold various data types and optional tags, providing a flexible way
@@ -49,12 +49,15 @@ abstract class CborObject {
4949
} else if (value is List<List<int>>) {
5050
return CborDynamicBytesValue(value);
5151
} else if (value is Map) {
52-
return CborMapValue.fixedLength(value);
52+
return CborMapValue.fixedLength({
53+
for (final i in value.entries)
54+
CborObject.fromDynamic(i.key): CborObject.fromDynamic(i.value)
55+
});
5356
} else if (value is List<dynamic>) {
5457
return CborListValue.fixedLength(
5558
value.map((e) => CborObject.fromDynamic(e)).toList());
5659
}
57-
throw UnimplementedError("does not supported");
60+
throw const CborException("does not supported");
5861
}
5962
}
6063

@@ -73,7 +76,7 @@ abstract class CborNumeric implements CborObject {
7376
} else if (val is CborSafeIntValue) {
7477
return val.value;
7578
}
76-
throw const ArgumentException("invalid cbornumeric");
79+
throw const CborException("invalid cbornumeric");
7780
}
7881

7982
/// Convert the CborNumeric object to an integer.

lib/cbor/exception/exception.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import 'package:blockchain_utils/exception/exceptions.dart';
2+
3+
class CborException extends BlockchainUtilsException {
4+
const CborException(String message, {Map<String, dynamic>? details})
5+
: super(message, details: details);
6+
}

lib/cbor/types/bytes.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ class CborBytesValue implements CborObject {
1010
/// It accepts the bytes value.
1111
CborBytesValue(List<int> value) : value = value.asImmutableBytes;
1212

13-
/// The value as a List<int>.
14-
@override
1513
final List<int> value;
1614

1715
/// Encode the value into CBOR bytes
@@ -51,6 +49,8 @@ class CborDynamicBytesValue implements CborObject {
5149

5250
@override
5351
final List<List<int>> value;
52+
// @override
53+
// List<List<int>> get value => _value;
5454

5555
/// Encode the value into CBOR bytes
5656
@override
@@ -82,7 +82,7 @@ class CborDynamicBytesValue implements CborObject {
8282
operator ==(other) {
8383
if (other is! CborDynamicBytesValue) return false;
8484

85-
return value == other.value;
85+
return CompareUtils.iterableIsEqual(value, other.value);
8686
}
8787

8888
/// ovveride hash code

lib/cbor/types/cbor_tag.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class CborTagValue<T> implements CborObject {
2222
List<int> encode() {
2323
final bytes = CborBytesTracker();
2424
bytes.pushTags(tags);
25-
final obj = CborObject.fromDynamic(value).encode();
25+
final obj = CborObject.fromDynamic(_value).encode();
2626
bytes.pushBytes(obj);
2727
return bytes.toBytes();
2828
}

lib/cbor/types/decimal.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ class CborDecimalFracValue implements CborObject {
1313

1414
/// Create a CborBigFloatValue from two CborNumeric values representing the exponent and mantissa.
1515
factory CborDecimalFracValue.fromCborNumeric(
16-
CborNumeric exponent,
17-
CborNumeric mantissa,
18-
) {
16+
CborNumeric exponent, CborNumeric mantissa) {
1917
return CborDecimalFracValue(CborNumeric.getCborNumericValue(exponent),
2018
CborNumeric.getCborNumericValue(mantissa));
2119
}

lib/cbor/types/int.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:blockchain_utils/cbor/core/cbor.dart';
2+
import 'package:blockchain_utils/cbor/exception/exception.dart';
23
import 'package:blockchain_utils/cbor/utils/dynamic_bytes.dart';
34
import 'package:blockchain_utils/cbor/core/tags.dart';
45
import 'package:blockchain_utils/utils/utils.dart';
@@ -20,10 +21,13 @@ class CborIntValue implements CborNumeric {
2021
List<int> encode() {
2122
final bytes = CborBytesTracker();
2223
if (value.bitLength > 31 && value.isNegative) {
23-
final value = (~BigInt.parse(this.value.toString())).toInt();
24-
bytes.pushInt(MajorTags.negInt, value);
24+
final value = (~BigInt.parse(this.value.toString()));
25+
if (!value.isValidInt) {
26+
throw CborException("Value is to large for encoding as CborInteger",
27+
details: {"value": this.value.toString()});
28+
}
29+
bytes.pushInt(MajorTags.negInt, value.toInt());
2530
} else {
26-
// print("is here lower!");
2731
bytes.pushInt(value.isNegative ? MajorTags.negInt : MajorTags.posInt,
2832
value.isNegative ? ~value : value);
2933
}

lib/cbor/types/list.dart

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:blockchain_utils/helper/helper.dart';
21
import 'package:blockchain_utils/utils/utils.dart';
32
import 'package:blockchain_utils/cbor/utils/dynamic_bytes.dart';
43
import 'package:blockchain_utils/cbor/core/tags.dart';
@@ -9,18 +8,13 @@ class CborListValue<T> implements CborObject {
98
/// Constructor for creating a CborListValue instance with the provided parameters.
109
/// It accepts the List of all cbor encodable value.
1110
///
12-
CborListValue.fixedLength(List<T> value)
13-
: value = value.immutable,
14-
_isFixedLength = true;
11+
CborListValue.fixedLength(this.value) : _isFixedLength = true;
1512

1613
/// Constructor for creating a CborListValue instance with the provided parameters.
1714
/// It accepts the List of all cbor encodable value.
1815
/// this method encode values with indefinite tag.
19-
CborListValue.dynamicLength(List<T> value)
20-
: value = value.immutable,
21-
_isFixedLength = false;
16+
CborListValue.dynamicLength(this.value) : _isFixedLength = false;
2217

23-
/// value as List
2418
@override
2519
final List<T> value;
2620

lib/cbor/types/map.dart

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:blockchain_utils/helper/helper.dart';
21
import 'package:blockchain_utils/utils/utils.dart';
32
import 'package:blockchain_utils/cbor/utils/dynamic_bytes.dart';
43
import 'package:blockchain_utils/cbor/core/tags.dart';
@@ -8,16 +7,12 @@ import 'package:blockchain_utils/cbor/core/cbor.dart';
87
class CborMapValue<K, V> implements CborObject {
98
/// Constructor for creating a CborMapValue instance with the provided parameters.
109
/// It accepts the Map with all cbor encodable key and value.
11-
CborMapValue.fixedLength(Map<K, V> value)
12-
: value = value.immutable,
13-
_isFixedLength = true;
10+
CborMapValue.fixedLength(this.value) : _isFixedLength = true;
1411

1512
/// Constructor for creating a CborMapValue instance with the provided parameters.
1613
/// It accepts the Map with all cbor encodable key and value.
1714
/// this method encode values with indefinite tag.
18-
CborMapValue.dynamicLength(Map<K, V> value)
19-
: value = value.immutable,
20-
_isFixedLength = false;
15+
CborMapValue.dynamicLength(this.value) : _isFixedLength = false;
2116

2217
/// value as Map
2318
@override

lib/cbor/types/set.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'package:blockchain_utils/cbor/core/cbor.dart';
77
class CborSetValue<T> implements CborObject {
88
/// Constructor for creating a CborSetValue instance with the provided parameters.
99
/// It accepts a set of all encodable cbor object.
10-
CborSetValue(Set<T> value) : value = Set.unmodifiable(value);
10+
CborSetValue(this.value);
1111

1212
/// value as set
1313
@override

lib/cbor/types/string.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ class CborIndefiniteStringValue extends CborString {
6161
/// It accepts a List<String> value.
6262
CborIndefiniteStringValue(List<String> value) : value = value.immutable;
6363

64-
/// value as List<String>
6564
@override
6665
final List<String> value;
6766

lib/cbor/utils/cbor_utils.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import 'dart:typed_data';
22
import 'package:blockchain_utils/cbor/core/cbor.dart';
3+
import 'package:blockchain_utils/cbor/exception/exception.dart';
34
import 'package:blockchain_utils/cbor/types/types.dart';
45
import 'package:blockchain_utils/cbor/utils/float_utils.dart';
56
import 'package:blockchain_utils/cbor/core/tags.dart';
6-
import 'package:blockchain_utils/exception/exception.dart';
77
import 'package:blockchain_utils/utils/utils.dart';
88

99
class CborUtils {
@@ -23,7 +23,7 @@ class CborUtils {
2323
// Split the string into the date and offset parts
2424
final parts = dateTimeString.split('+');
2525
if (parts.length != 2) {
26-
throw MessageException("Invalid format: $dateTimeString");
26+
throw CborException("Invalid RFC3339 format: $dateTimeString");
2727
}
2828
final datePart = DateTime.parse(parts[0]);
2929
return datePart;
@@ -66,11 +66,11 @@ class CborUtils {
6666
}
6767
return _decodeArray(cborBytes, i, info, tags);
6868
default:
69-
throw ArgumentException(
69+
throw CborException(
7070
"invalid or unsuported cbor tag major: $majorTag ");
7171
}
7272
}
73-
throw const ArgumentException("invalid or unsuported cbor tag");
73+
throw const CborException("invalid or unsuported cbor tag");
7474
}
7575

7676
static Tuple<List<int>, int> _parsBytes(int info, List<int> cborBytes) {
@@ -96,7 +96,7 @@ class CborUtils {
9696
}
9797
return Tuple(decode, len + 1);
9898
} else {
99-
throw ArgumentException('Invalid additional info for int: $info');
99+
throw CborException('Invalid additional info for int: $info');
100100
}
101101
}
102102

@@ -254,7 +254,7 @@ class CborUtils {
254254
List<CborObject> objects, List<int> tags) {
255255
objects = objects.whereType<CborNumeric>().toList();
256256
if (objects.length != 2) {
257-
throw const MessageException("invalid bigFloat array length");
257+
throw const CborException("invalid bigFloat array length");
258258
}
259259
if (BytesUtils.bytesEqual(tags, CborTags.decimalFrac)) {
260260
tags.clear();
@@ -313,7 +313,7 @@ class CborUtils {
313313
offset = offset + 8;
314314
break;
315315
default:
316-
throw const MessageException("Invalid simpleOrFloatTags");
316+
throw const CborException("Invalid simpleOrFloatTags");
317317
}
318318
if (BytesUtils.bytesEqual(tags, CborTags.dateEpoch)) {
319319
final dt = DateTime.fromMillisecondsSinceEpoch((val * 1000).round());

lib/cbor/utils/float_utils.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import 'dart:math' as math;
1717
import 'dart:typed_data';
1818

1919
import 'package:blockchain_utils/cbor/core/tags.dart';
20-
import 'package:blockchain_utils/exception/exception.dart';
20+
import 'package:blockchain_utils/cbor/exception/exception.dart';
2121
import 'package:blockchain_utils/utils/utils.dart';
2222

2323
// Enum representing different floating-point formats and their characteristics.
@@ -60,7 +60,7 @@ class FloatLength {
6060
if (index >= 0 && index < values.length) {
6161
return values[index];
6262
}
63-
throw MessageException('Index out of bounds', details: {"input": index});
63+
throw CborException('Index out of bounds', details: {"input": index});
6464
}
6565
}
6666

@@ -242,13 +242,13 @@ class FloatUtils {
242242
switch (decodFloatType) {
243243
case FloatLength.bytes16:
244244
if (!isLessThan16) {
245-
throw const ArgumentException("overflow bytes");
245+
throw const CborException("overflow bytes");
246246
}
247247
bytes = _encodeFloat16(endianness);
248248
break;
249249
case FloatLength.bytes32:
250250
if (!isLessThan32) {
251-
throw const ArgumentException("overflow bytes");
251+
throw const CborException("overflow bytes");
252252
}
253253
bytes = _encodeFloat32(endianness);
254254
break;
@@ -262,7 +262,7 @@ class FloatUtils {
262262
/// Decode a 16-bit floating-point value from a byte array and return it as a double.
263263
static double floatFromBytes16(List<int> bytes) {
264264
if (bytes.length != 2) {
265-
throw const ArgumentException(
265+
throw const CborException(
266266
'Input byte array must be exactly 2 bytes long for Float16');
267267
}
268268

lib/utils/compare/compare.dart

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,49 @@ class CompareUtils {
2121

2222
/// Compare the individual byte values in 'a' and 'b'.
2323
for (int index = 0; index < a.length; index += 1) {
24-
if (a.elementAt(index) != b.elementAt(index)) {
24+
final valueA = a.elementAt(index);
25+
final valueB = b.elementAt(index);
26+
if (valueA is Map && valueB is Map) {
27+
// Recursively compare maps
28+
if (!mapIsEqual(valueA, valueB)) return false;
29+
} else if (valueA is Iterable && valueB is Iterable) {
30+
// Recursively compare iterables
31+
if (!iterableIsEqual(valueA, valueB)) return false;
32+
} else if (valueA != valueB) {
2533
return false;
2634
}
2735
}
2836

2937
/// If no differences were found, the lists are equal.
3038
return true;
3139
}
40+
41+
static bool mapIsEqual<K, V>(Map<K, V>? a, Map<K, V>? b) {
42+
// Handle null comparison
43+
if (a == null) return b == null;
44+
if (b == null || a.length != b.length) return false;
45+
46+
// Check if 'a' and 'b' are identical objects
47+
if (identical(a, b)) return true;
48+
49+
// Compare the entries in 'a' and 'b'
50+
for (final key in a.keys) {
51+
if (!b.containsKey(key)) return false;
52+
53+
final valueA = a[key];
54+
final valueB = b[key];
55+
56+
if (valueA is Map && valueB is Map) {
57+
// Recursively compare maps
58+
if (!mapIsEqual(valueA, valueB)) return false;
59+
} else if (valueA is Iterable && valueB is Iterable) {
60+
// Recursively compare iterables
61+
if (!iterableIsEqual(valueA, valueB)) return false;
62+
} else if (valueA != valueB) {
63+
return false;
64+
}
65+
}
66+
67+
return true;
68+
}
3269
}

0 commit comments

Comments
 (0)