From 832f38af9e4a676d1f47c302785e8a00d3fc72a9 Mon Sep 17 00:00:00 2001 From: Hoylen Sue Date: Fri, 26 Aug 2022 19:00:43 +1000 Subject: [PATCH] Fixed parse to allow buffers larger than 16 bytes to be used. --- CHANGELOG.md | 4 ++++ lib/uuid.dart | 41 ++++++++++++++++++++++++++++++++++------- test/uuid_test.dart | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4afcbe..6232e6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v3.0.7 + +* Fixed parse to allow buffers larger than 16 bytes to be used. + v3.0.6 * Enable `avoid_dynamic_calls` linting and fix appropriately. (Thanks @devoncarew) diff --git a/lib/uuid.dart b/lib/uuid.dart index 32fdb79..32de060 100644 --- a/lib/uuid.dart +++ b/lib/uuid.dart @@ -112,11 +112,22 @@ class Uuid { } } - ///Parses the provided [uuid] into a list of byte values as a List. + /// Parses the provided [uuid] into a list of byte values as a List. + /// /// Can optionally be provided a [buffer] to write into and - /// a positional [offset] for where to start inputting into the buffer. + /// a positional [offset] for where to start inputting into the buffer. + /// + /// Returns the buffer containing the bytes. If no buffer was provided, + /// a new buffer is created and returned. If a _buffer_ was provided, it + /// is returned (even if the uuid bytes are not placed at the beginning of + /// that buffer). + /// /// Throws FormatException if the UUID is invalid. Optionally you can set /// [validate] to false to disable validation of the UUID before parsing. + /// + /// Throws _RangeError_ if a _buffer_ is provided and it is too small. + /// It is also thrown if a non-zero _offset_ is provided without providing + /// a _buffer_. static List parse( String uuid, { List? buffer, @@ -129,8 +140,20 @@ class Uuid { } var i = offset, ii = 0; - // Create a 16 item buffer if one hasn't been provided. - buffer = (buffer != null) ? buffer : Uint8List(16); + // Get buffer to store the result + if (buffer == null) { + // Buffer not provided: create a 16 item buffer + if (offset != 0) { + throw RangeError('non-zero offset without providing a buffer'); + } + buffer = Uint8List(16); + } else { + // Buffer provided: check it is large enough + if (buffer.length - offset < 16) { + throw RangeError('buffer too small: need 16: length=${buffer.length}' + '${offset != 0 ? ', offset=$offset' : ''}'); + } + } // Convert to lowercase and replace all hex with bytes then // string.replaceAll() does a lot of work that I don't need, and a manual @@ -171,10 +194,14 @@ class Uuid { /// Unparses a [buffer] of bytes and outputs a proper UUID string. /// An optional [offset] is allowed if you want to start at a different point /// in the buffer. - /// Throws an exception if the buffer does not have a length of 16 + /// + /// Throws a [RangeError] exception if the _buffer_ is not large enough to + /// hold the bytes. That is, if the length of the _buffer_ after the _offset_ + /// is less than 16. static String unparse(List buffer, {int offset = 0}) { - if (buffer.length != 16) { - throw Exception('The provided buffer needs to have a length of 16.'); + if (buffer.length - offset < 16) { + throw RangeError('buffer too small: need 16: length=${buffer.length}' + '${offset != 0 ? ', offset=$offset' : ''}'); } var i = offset; return '${_byteToHex[buffer[i++]]}${_byteToHex[buffer[i++]]}' diff --git a/test/uuid_test.dart b/test/uuid_test.dart index 7d4771f..d132ef7 100644 --- a/test/uuid_test.dart +++ b/test/uuid_test.dart @@ -261,6 +261,44 @@ void main() { expect(() => Uuid.unparse(Uuid.parse('(this is the uuid -> $id$id')), throwsA(isA())); }); + + group('buffer:', () { + const size = 64; + final buffer = Uint8List(size); + + group('offset good:', () { + for (final testCase in { + 'offset=0': 0, + 'offset=1': 1, + 'offset in the middle': 32, + 'offset 16 bytes before the end': size - 16, + }.entries) { + test(testCase.key, () { + final v = Uuid.parse(Uuid.NAMESPACE_OID, + buffer: buffer, offset: testCase.value); + + expect(Uuid.unparse(v, offset: testCase.value), + equals(Uuid.NAMESPACE_OID)); + }); + } + }); + + group('offset bad:', () { + for (final testCase in { + 'offset 15 bytes before end': size - 15, + 'offset at end of buffer': size, + 'offset after end of buffer': size + 1, + 'offset is negative': -1 + }.entries) { + test(testCase.key, () { + expect( + () => Uuid.parse(Uuid.NAMESPACE_OID, + buffer: buffer, offset: testCase.value), + throwsA(isA())); + }); + } + }); + }); }); group('[UuidValue]', () {