From ecf64ec06487bc7463df5a62c5f3160f88ca9dea Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 13:46:29 +0000 Subject: [PATCH 1/8] Update XsdShortCodec to use typed_data --- lib/src/codecs/short/short_decoder.dart | 27 +++++++++++++++---------- lib/src/codecs/short/short_encoder.dart | 13 +++++++----- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/src/codecs/short/short_decoder.dart b/lib/src/codecs/short/short_decoder.dart index c421d85..1ff937b 100644 --- a/lib/src/codecs/short/short_decoder.dart +++ b/lib/src/codecs/short/short_decoder.dart @@ -1,30 +1,35 @@ import 'dart:convert'; +import 'dart:typed_data'; import '../../helpers/whitespace.dart'; class XsdShortDecoder extends Converter { const XsdShortDecoder(); - static const int _minValue = -32768; - static const int _maxValue = 32767; - @override int convert(String input) { - final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); + final str = processWhiteSpace(input, Whitespace.collapse); + + if (str.isEmpty) { + throw const FormatException('The input string cannot be empty.'); + } + + final value = int.tryParse(str); - final int? value = int.tryParse(collapsedInput); if (value == null) { - throw FormatException( - "Invalid XSD short lexical format: '$input' (collapsed to '$collapsedInput')", - ); + throw FormatException('The input "$str" is not a valid integer.'); } - // Check bounds for xsd:short - if (value < _minValue || value > _maxValue) { + // Use Int16List to validate that the value fits within 16 bits (wraps on overflow). + final list = Int16List(1); + list[0] = value; + + if (list[0] != value) { throw FormatException( - "Value '$collapsedInput' is out of range for xsd:short. Must be between $_minValue and $_maxValue.", + 'The value "$value" is out of range for xsd:short.', ); } + return value; } } diff --git a/lib/src/codecs/short/short_encoder.dart b/lib/src/codecs/short/short_encoder.dart index 2a40fb8..284ee7a 100644 --- a/lib/src/codecs/short/short_encoder.dart +++ b/lib/src/codecs/short/short_encoder.dart @@ -1,18 +1,21 @@ import 'dart:convert'; +import 'dart:typed_data'; +/// A [Converter] that converts an [int] to an XSD `short` string. class XsdShortEncoder extends Converter { const XsdShortEncoder(); - static const int _minValue = -32768; - static const int _maxValue = 32767; - @override String convert(int input) { - if (input < _minValue || input > _maxValue) { + // Use Int16List to validate that the value fits within 16 bits (wraps on overflow). + final list = Int16List(1); + list[0] = input; + if (list[0] != input) { throw FormatException( - "Value '$input' is out of range for xsd:short. Must be between $_minValue and $_maxValue.", + 'The value "$input" is out of range for xsd:short.', ); } + return input.toString(); } } From d72c06906bc755f8257f2d9956ceb16ee6b617a0 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 13:47:06 +0000 Subject: [PATCH 2/8] Update XsdByteCodec to use typed_data --- lib/src/codecs/byte/byte_decoder.dart | 23 ++++++++--------------- lib/src/codecs/byte/byte_encoder.dart | 14 +++++++------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/lib/src/codecs/byte/byte_decoder.dart b/lib/src/codecs/byte/byte_decoder.dart index 1868938..6028a0d 100644 --- a/lib/src/codecs/byte/byte_decoder.dart +++ b/lib/src/codecs/byte/byte_decoder.dart @@ -1,39 +1,32 @@ import 'dart:convert'; +import 'dart:typed_data'; import '../../helpers/whitespace.dart'; class XsdByteDecoder extends Converter { const XsdByteDecoder(); - static const int _minValue = -128; - static const int _maxValue = 127; - @override int convert(String input) { final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); final int? value = int.tryParse(collapsedInput); if (value == null) { - // If int.tryParse fails, it could be a lexical error or a number too large - // for a platform int. We use BigInt.tryParse to differentiate. - if (BigInt.tryParse(collapsedInput) != null) { - // The string is a valid integer, but it's too large to be parsed as a - // platform int, so it's definitely out of range for xsd:byte. - throw FormatException( - "Value '$collapsedInput' is out of range for xsd:byte. Must be between $_minValue and $_maxValue.", - ); - } throw FormatException( "Invalid xsd:byte lexical format: '$input' (collapsed to '$collapsedInput')", ); } - if (value < _minValue || value > _maxValue) { + // Use Int8List to validate that the value fits within 8 bits (wraps on overflow). + final list = Int8List(1); + list[0] = value; + + if (list[0] != value) { throw FormatException( - "Value '$collapsedInput' is out of range for xsd:byte. Must be between $_minValue and $_maxValue.", + "Value '$collapsedInput' is out of range for xsd:byte.", ); } return value; } -} +} \ No newline at end of file diff --git a/lib/src/codecs/byte/byte_encoder.dart b/lib/src/codecs/byte/byte_encoder.dart index 8aef792..cbba3ad 100644 --- a/lib/src/codecs/byte/byte_encoder.dart +++ b/lib/src/codecs/byte/byte_encoder.dart @@ -1,17 +1,17 @@ import 'dart:convert'; +import 'dart:typed_data'; +/// A [Converter] that converts an [int] to an XSD `byte` compatable string. class XsdByteEncoder extends Converter { const XsdByteEncoder(); - static const int _minValue = -128; - static const int _maxValue = 127; - @override String convert(int input) { - if (input < _minValue || input > _maxValue) { - throw FormatException( - "Value '$input' is out of range for xsd:byte. Must be between $_minValue and $_maxValue.", - ); + // Use Int8List to validate that the value fits within 8 bits (wraps on overflow). + final list = Int8List(1); + list[0] = input; + if (list[0] != input) { + throw FormatException("Value '$input' is out of range for xsd:byte."); } return input.toString(); } From d7a9e3f8fb9e8d7e372a8968c6c555f8f42d1ab8 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 13:50:22 +0000 Subject: [PATCH 3/8] Update XsdIntCodec to use typed_data --- lib/src/codecs/int/int_decoder.dart | 21 +++++++-------------- lib/src/codecs/int/int_encoder.dart | 13 ++++++------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/lib/src/codecs/int/int_decoder.dart b/lib/src/codecs/int/int_decoder.dart index 3a33bbc..ab083f5 100644 --- a/lib/src/codecs/int/int_decoder.dart +++ b/lib/src/codecs/int/int_decoder.dart @@ -1,36 +1,29 @@ import 'dart:convert'; +import 'dart:typed_data'; import '../../helpers/whitespace.dart'; class XsdIntDecoder extends Converter { const XsdIntDecoder(); - static const int _minValue = -2147483648; - static const int _maxValue = 2147483647; - @override int convert(String input) { final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); final int? value = int.tryParse(collapsedInput); if (value == null) { - // If int.tryParse fails, it could be a lexical error or a number too large - // for a platform int. We use BigInt.tryParse to differentiate. - if (BigInt.tryParse(collapsedInput) != null) { - // The string is a valid integer, but it's too large to be parsed as a - // platform int, so it's definitely out of range for xsd:int. - throw FormatException( - "Value '$collapsedInput' is out of range for xsd:int. Must be between $_minValue and $_maxValue.", - ); - } throw FormatException( "Invalid XSD int lexical format: '$input' (collapsed to '$collapsedInput')", ); } - if (value < _minValue || value > _maxValue) { + // Use Int32List to validate that the value fits within 32 bits (wraps on overflow). + final list = Int32List(1); + list[0] = value; + + if (list[0] != value) { throw FormatException( - "Value '$collapsedInput' is out of range for xsd:int. Must be between $_minValue and $_maxValue.", + "Value '$collapsedInput' is out of range for xsd:int.", ); } return value; diff --git a/lib/src/codecs/int/int_encoder.dart b/lib/src/codecs/int/int_encoder.dart index c564e80..b5a3e7b 100644 --- a/lib/src/codecs/int/int_encoder.dart +++ b/lib/src/codecs/int/int_encoder.dart @@ -1,17 +1,16 @@ import 'dart:convert'; +import 'dart:typed_data'; class XsdIntEncoder extends Converter { const XsdIntEncoder(); - static const int _minValue = -2147483648; - static const int _maxValue = 2147483647; - @override String convert(int input) { - if (input < _minValue || input > _maxValue) { - throw FormatException( - "Value '$input' is out of range for xsd:int. Must be between $_minValue and $_maxValue.", - ); + // Use Int32List to validate that the value fits within 32 bits (wraps on overflow). + final list = Int32List(1); + list[0] = input; + if (list[0] != input) { + throw FormatException("Value '$input' is out of range for xsd:int."); } return input.toString(); } From 76600f0955ec5d680171bb249908979f47c63205 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 13:53:06 +0000 Subject: [PATCH 4/8] Update XsdUnsignedByteCodec to use typed_data --- .../codecs/unsigned_byte/unsigned_byte_decoder.dart | 12 +++++++----- .../codecs/unsigned_byte/unsigned_byte_encoder.dart | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart b/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart index 9c60948..b0fda6a 100644 --- a/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart +++ b/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart @@ -1,13 +1,11 @@ import 'dart:convert'; +import 'dart:typed_data'; import '../../helpers/whitespace.dart'; class XsdUnsignedByteDecoder extends Converter { const XsdUnsignedByteDecoder(); - static const int _minValue = 0; - static const int _maxValue = 255; - @override int convert(String input) { final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); @@ -19,9 +17,13 @@ class XsdUnsignedByteDecoder extends Converter { ); } - if (value < _minValue || value > _maxValue) { + // Use Uint8List to validate that the value fits within 8 bits (wraps on overflow). + final list = Uint8List(1); + list[0] = value; + + if (list[0] != value) { throw FormatException( - "Value '$collapsedInput' is out of range for xsd:unsignedByte. Must be between $_minValue and $_maxValue.", + "Value '$collapsedInput' is out of range for xsd:unsignedByte.", ); } return value; diff --git a/lib/src/codecs/unsigned_byte/unsigned_byte_encoder.dart b/lib/src/codecs/unsigned_byte/unsigned_byte_encoder.dart index bcde152..d7bb2c1 100644 --- a/lib/src/codecs/unsigned_byte/unsigned_byte_encoder.dart +++ b/lib/src/codecs/unsigned_byte/unsigned_byte_encoder.dart @@ -1,16 +1,18 @@ import 'dart:convert'; +import 'dart:typed_data'; +/// A [Converter] that converts an [int] to an XSD `unsignedByte` string. class XsdUnsignedByteEncoder extends Converter { const XsdUnsignedByteEncoder(); - static const int _minValue = 0; - static const int _maxValue = 255; - @override String convert(int input) { - if (input < _minValue || input > _maxValue) { + // Use Uint8List to validate that the value fits within 8 bits (wraps on overflow). + final list = Uint8List(1); + list[0] = input; + if (list[0] != input) { throw FormatException( - "Value '$input' is out of range for xsd:unsignedByte. Must be between $_minValue and $_maxValue.", + "Value '$input' is out of range for xsd:unsignedByte.", ); } return input.toString(); From 411d305a85e92febede6e79aeae9a2aaf8ccba9d Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 13:56:01 +0000 Subject: [PATCH 5/8] Rename Unsigned Short Codec --- lib/src/codecs/unsigned_short/unsigned_short_codec.dart | 8 ++++---- lib/src/codecs/unsigned_short/unsigned_short_decoder.dart | 4 ++-- lib/src/codecs/unsigned_short/unsigned_short_encoder.dart | 4 ++-- test/codecs/unsigned_short_codec_test.dart | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/src/codecs/unsigned_short/unsigned_short_codec.dart b/lib/src/codecs/unsigned_short/unsigned_short_codec.dart index fa88403..2a555cb 100644 --- a/lib/src/codecs/unsigned_short/unsigned_short_codec.dart +++ b/lib/src/codecs/unsigned_short/unsigned_short_codec.dart @@ -3,12 +3,12 @@ import 'dart:convert'; import 'unsigned_short_decoder.dart'; import 'unsigned_short_encoder.dart'; -class XmlUnsignedShortCodec extends Codec { - const XmlUnsignedShortCodec(); +class XsdUnsignedShortCodec extends Codec { + const XsdUnsignedShortCodec(); @override - Converter get decoder => const XmlUnsignedShortDecoder(); + Converter get decoder => const XsdUnsignedShortDecoder(); @override - Converter get encoder => const XmlUnsignedShortEncoder(); + Converter get encoder => const XsdUnsignedShortEncoder(); } diff --git a/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart b/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart index c8e8824..1eb1a64 100644 --- a/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart +++ b/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart @@ -2,8 +2,8 @@ import 'dart:convert'; import '../../helpers/whitespace.dart'; -class XmlUnsignedShortDecoder extends Converter { - const XmlUnsignedShortDecoder(); +class XsdUnsignedShortDecoder extends Converter { + const XsdUnsignedShortDecoder(); static const int _minValue = 0; static const int _maxValue = 65535; diff --git a/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart b/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart index 985bd06..72390ca 100644 --- a/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart +++ b/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart @@ -1,7 +1,7 @@ import 'dart:convert'; -class XmlUnsignedShortEncoder extends Converter { - const XmlUnsignedShortEncoder(); +class XsdUnsignedShortEncoder extends Converter { + const XsdUnsignedShortEncoder(); static const int _minValue = 0; static const int _maxValue = 65535; diff --git a/test/codecs/unsigned_short_codec_test.dart b/test/codecs/unsigned_short_codec_test.dart index 2a86c41..c8bd48f 100644 --- a/test/codecs/unsigned_short_codec_test.dart +++ b/test/codecs/unsigned_short_codec_test.dart @@ -2,8 +2,8 @@ import 'package:test/test.dart'; import 'package:xsd/src/codecs/unsigned_short/unsigned_short_codec.dart'; void main() { - test('XML Unsigned Short Codec -> Decode', () { - const codec = XmlUnsignedShortCodec(); + test('XSD Unsigned Short Codec -> Decode', () { + const codec = XsdUnsignedShortCodec(); final decoder = codec.decoder; expect(decoder.convert('12345'), equals(12345)); @@ -16,7 +16,7 @@ void main() { }); test('XML Unsigned Short Codec -> Encode', () { - const codec = XmlUnsignedShortCodec(); + const codec = XsdUnsignedShortCodec(); final encoder = codec.encoder; expect(encoder.convert(12345), equals('12345')); From d3d2c89a09396c13bcff333da6e4eb5ca27388ae Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 13:58:24 +0000 Subject: [PATCH 6/8] Update XsdUnsignedShort to use typed_data --- .../unsigned_short/unsigned_short_decoder.dart | 12 +++++++----- .../unsigned_short/unsigned_short_encoder.dart | 13 +++++++------ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart b/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart index 1eb1a64..5af528d 100644 --- a/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart +++ b/lib/src/codecs/unsigned_short/unsigned_short_decoder.dart @@ -1,13 +1,11 @@ import 'dart:convert'; +import 'dart:typed_data'; import '../../helpers/whitespace.dart'; class XsdUnsignedShortDecoder extends Converter { const XsdUnsignedShortDecoder(); - static const int _minValue = 0; - static const int _maxValue = 65535; - @override int convert(String input) { final str = processWhiteSpace(input, Whitespace.collapse); @@ -22,9 +20,13 @@ class XsdUnsignedShortDecoder extends Converter { throw FormatException('The input "$str" is not a valid integer.'); } - if (value < _minValue || value > _maxValue) { + // Use Uint16List to validate that the value fits within 16 bits (wraps on overflow). + final list = Uint16List(1); + list[0] = value; + + if (list[0] != value) { throw FormatException( - 'The value "$value" must be between $_minValue and $_maxValue.', + 'The value "$value" is out of range for xsd:unsignedShort.', ); } diff --git a/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart b/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart index 72390ca..e91896d 100644 --- a/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart +++ b/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart @@ -1,16 +1,17 @@ import 'dart:convert'; +import 'dart:typed_data'; class XsdUnsignedShortEncoder extends Converter { const XsdUnsignedShortEncoder(); - static const int _minValue = 0; - static const int _maxValue = 65535; - - @override + @override String convert(int input) { - if (input < _minValue || input > _maxValue) { + // Use Uint16List to validate that the value fits within 16 bits (wraps on overflow). + final list = Uint16List(1); + list[0] = input; + if (list[0] != input) { throw FormatException( - 'The value "$input" must be between $_minValue and $_maxValue.', + 'The value "$input" is out of range for xsd:unsignedShort.', ); } From cac367fa55e06285bc270d7206a92a8bd3e7b113 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 14:00:14 +0000 Subject: [PATCH 7/8] Run dart format --- lib/src/codecs/byte/byte_decoder.dart | 2 +- lib/src/codecs/unsigned_short/unsigned_short_encoder.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/codecs/byte/byte_decoder.dart b/lib/src/codecs/byte/byte_decoder.dart index 6028a0d..7cbcbee 100644 --- a/lib/src/codecs/byte/byte_decoder.dart +++ b/lib/src/codecs/byte/byte_decoder.dart @@ -29,4 +29,4 @@ class XsdByteDecoder extends Converter { return value; } -} \ No newline at end of file +} diff --git a/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart b/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart index e91896d..65713b4 100644 --- a/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart +++ b/lib/src/codecs/unsigned_short/unsigned_short_encoder.dart @@ -4,7 +4,7 @@ import 'dart:typed_data'; class XsdUnsignedShortEncoder extends Converter { const XsdUnsignedShortEncoder(); - @override + @override String convert(int input) { // Use Uint16List to validate that the value fits within 16 bits (wraps on overflow). final list = Uint16List(1); From f6dabba28ab161e4895c0885ce3cc321f3e62314 Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 27 Nov 2025 14:16:55 +0000 Subject: [PATCH 8/8] Add some more explicit checks for blank inputs --- lib/src/codecs/byte/byte_decoder.dart | 4 ++++ lib/src/codecs/int/int_decoder.dart | 4 ++++ lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/lib/src/codecs/byte/byte_decoder.dart b/lib/src/codecs/byte/byte_decoder.dart index 7cbcbee..81233a0 100644 --- a/lib/src/codecs/byte/byte_decoder.dart +++ b/lib/src/codecs/byte/byte_decoder.dart @@ -10,6 +10,10 @@ class XsdByteDecoder extends Converter { int convert(String input) { final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); + if (collapsedInput.isEmpty) { + throw const FormatException('The input string cannot be empty.'); + } + final int? value = int.tryParse(collapsedInput); if (value == null) { throw FormatException( diff --git a/lib/src/codecs/int/int_decoder.dart b/lib/src/codecs/int/int_decoder.dart index ab083f5..84415db 100644 --- a/lib/src/codecs/int/int_decoder.dart +++ b/lib/src/codecs/int/int_decoder.dart @@ -10,6 +10,10 @@ class XsdIntDecoder extends Converter { int convert(String input) { final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); + if (collapsedInput.isEmpty) { + throw const FormatException('The input string cannot be empty.'); + } + final int? value = int.tryParse(collapsedInput); if (value == null) { throw FormatException( diff --git a/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart b/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart index b0fda6a..62d5006 100644 --- a/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart +++ b/lib/src/codecs/unsigned_byte/unsigned_byte_decoder.dart @@ -10,6 +10,10 @@ class XsdUnsignedByteDecoder extends Converter { int convert(String input) { final String collapsedInput = processWhiteSpace(input, Whitespace.collapse); + if (collapsedInput.isEmpty) { + throw const FormatException('The input string cannot be empty.'); + } + final int? value = int.tryParse(collapsedInput); if (value == null) { throw FormatException(