├── .gitignore ├── CHANGELOG.md ├── COPYING ├── LICENSE ├── README.md ├── lib └── hex.dart ├── pubspec.yaml └── test └── hex_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | packages 6 | # Remove the following pattern if you wish to check in your lock file 7 | pubspec.lock 8 | 9 | # Files created by dart2js 10 | *.dart.js 11 | *.part.js 12 | *.js.deps 13 | *.js.map 14 | *.info.json 15 | 16 | # Directory created by dartdoc 17 | doc/api/ 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.2.0 (2021-03-09) 4 | 5 | - Add null safety support 6 | - Require Dart SDK 2.12.0 or higher 7 | 8 | ## 0.1.2 (2018-08-13) 9 | 10 | - use `const` constructor for decoder 11 | - support Dart v2 12 | - change license to MIT 13 | 14 | ## 0.1.1 (2017-01-27) 15 | 16 | - throws `FormatException` on invalid input 17 | 18 | ## 0.1.0 (2017-01-27) 19 | 20 | - initial version 21 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | See UNLICENSE file. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dartcoin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dart-hex 2 | 3 | Easy hexadecimal encoding and decoding using the dart:convert API. 4 | 5 | ## Usage 6 | 7 | A simple usage example: 8 | 9 | ```dart 10 | import "package:hex/hex.dart"; 11 | 12 | void main() { 13 | HEX.encode(const [1, 2, 3]); // "010203" 14 | HEX.decode("010203"); // [1, 2, 3] 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /lib/hex.dart: -------------------------------------------------------------------------------- 1 | library hex; 2 | 3 | import "dart:convert"; 4 | import "dart:typed_data"; 5 | 6 | const String _ALPHABET = "0123456789abcdef"; 7 | 8 | /// An instance of the default implementation of the [HexCodec]. 9 | const HEX = const HexCodec(); 10 | 11 | /// A codec for encoding and decoding byte arrays to and from 12 | /// hexadecimal strings. 13 | class HexCodec extends Codec, String> { 14 | 15 | const HexCodec(); 16 | 17 | @override 18 | Converter, String> get encoder => const HexEncoder(); 19 | 20 | @override 21 | Converter> get decoder => const HexDecoder(); 22 | 23 | } 24 | 25 | /// A converter to encode byte arrays into hexadecimal strings. 26 | class HexEncoder extends Converter, String> { 27 | 28 | /// If true, the encoder will encode into uppercase hexadecimal strings. 29 | final bool upperCase; 30 | 31 | const HexEncoder({bool this.upperCase: false}); 32 | 33 | @override 34 | String convert(List bytes) { 35 | StringBuffer buffer = new StringBuffer(); 36 | for (int part in bytes) { 37 | if (part & 0xff != part) { 38 | throw new FormatException("Non-byte integer detected"); 39 | } 40 | buffer.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}'); 41 | } 42 | if(upperCase) { 43 | return buffer.toString().toUpperCase(); 44 | } else { 45 | return buffer.toString(); 46 | } 47 | } 48 | } 49 | 50 | /// A converter to decode hexadecimal strings into byte arrays. 51 | class HexDecoder extends Converter> { 52 | 53 | const HexDecoder(); 54 | 55 | @override 56 | List convert(String hex) { 57 | String str = hex.replaceAll(" ", ""); 58 | str = str.toLowerCase(); 59 | if(str.length % 2 != 0) { 60 | str = "0" + str; 61 | } 62 | Uint8List result = new Uint8List(str.length ~/ 2); 63 | for(int i = 0 ; i < result.length ; i++) { 64 | int firstDigit = _ALPHABET.indexOf(str[i*2]); 65 | int secondDigit = _ALPHABET.indexOf(str[i*2+1]); 66 | if (firstDigit == -1 || secondDigit == -1) { 67 | throw new FormatException("Non-hex character detected in $hex"); 68 | } 69 | result[i] = (firstDigit << 4) + secondDigit; 70 | } 71 | return result; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: hex 2 | description: Easy hexadecimal convertion using dart:convert API. 3 | version: 0.2.0 4 | author: Steven Roose 5 | homepage: https://github.com/stevenroose/dart-hex 6 | 7 | environment: 8 | sdk: '>=2.12.0 <3.0.0' 9 | 10 | dev_dependencies: 11 | test: ^1.16.0 12 | -------------------------------------------------------------------------------- /test/hex_test.dart: -------------------------------------------------------------------------------- 1 | import "package:hex/hex.dart"; 2 | import "package:test/test.dart"; 3 | 4 | Map> vectors = { 5 | "": const [], 6 | "0001020304050607": const [0, 1, 2, 3, 4, 5, 6, 7], 7 | "08090a0b0c0d0e0f": const [8, 9, 10, 11, 12, 13, 14, 15], 8 | "f0f1f2f3f4f5f6f7": const [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7], 9 | "f8f9fafbfcfdfeff": const [0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff], 10 | "e3a1": const [0xe3, 0xa1], 11 | }; 12 | 13 | void main() { 14 | test("encoding", () { 15 | vectors.forEach((hex, bytes) { 16 | expect(HEX.encode(bytes), equals(hex)); 17 | }); 18 | }); 19 | 20 | test("decoding", () { 21 | vectors.forEach((hex, bytes) { 22 | expect(HEX.decode(hex), orderedEquals(bytes)); 23 | }); 24 | }); 25 | 26 | test("encoding uppercase", () { 27 | vectors.forEach((hex, bytes) { 28 | expect(const HexEncoder(upperCase: true).convert(bytes), equals(hex.toUpperCase())); 29 | }); 30 | }); 31 | 32 | test("invalid characters", () { 33 | expect(() => HEX.decode("xx"), throwsFormatException); 34 | expect(() => HEX.encode(const [256]), throwsFormatException); 35 | }); 36 | } 37 | --------------------------------------------------------------------------------