base64Utils.dart 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import 'dart:convert';
  2. import 'dart:typed_data';
  3. import 'package:convert/convert.dart' show hex;
  4. /// Uint8List <--> Base64
  5. String bytesToBase64(Uint8List data, {bool urlSafe = false}) {
  6. try {
  7. if (data.isEmpty) {
  8. throw ArgumentError('Input data cannot be empty');
  9. }
  10. final base64Str = base64Encode(data);
  11. if (urlSafe) {
  12. return base64Str
  13. .replaceAll('+', '-')
  14. .replaceAll('/', '_')
  15. .replaceAll('=', '');
  16. }
  17. return base64Str;
  18. } on ArgumentError catch (e) {
  19. rethrow;
  20. } catch (e) {
  21. throw Exception('Failed to encode Uint8List to Base64: ${e.toString()}');
  22. }
  23. }
  24. Uint8List base64ToBytes(String base64Str, {bool? urlSafe}) {
  25. try {
  26. if (base64Str.isEmpty) {
  27. throw ArgumentError('Base64 string cannot be empty');
  28. }
  29. // 如果未指定 urlSafe,自动检测格式
  30. final isUrlSafe = urlSafe ??
  31. (base64Str.contains('-') || base64Str.contains('_'));
  32. String normalizedStr = base64Str;
  33. if (isUrlSafe) {
  34. // 添加必要的填充字符
  35. final padding = '=' * ((4 - base64Str.length % 4) % 4);
  36. normalizedStr = base64Str
  37. .replaceAll('-', '+')
  38. .replaceAll('_', '/') + padding;
  39. }
  40. // 验证 Base64 字符串格式
  41. if (!RegExp(r'^[a-zA-Z0-9+/]*={0,2}$').hasMatch(normalizedStr)) {
  42. throw FormatException('Invalid Base64 string format');
  43. }
  44. return base64Decode(normalizedStr);
  45. } on ArgumentError catch (e) {
  46. rethrow;
  47. } on FormatException catch (e) {
  48. rethrow;
  49. } catch (e) {
  50. throw Exception('Failed to decode Base64 to Uint8List: ${e.toString()}');
  51. }
  52. }
  53. /// 将十六进制字符串直接转换为 Base64
  54. ///
  55. /// [hexStr] 十六进制字符串
  56. /// [urlSafe] 是否生成URL安全的Base64
  57. ///
  58. /// 返回 Base64 字符串或抛出异常
  59. String hexToBase64(String hexStr, {bool urlSafe = false}) {
  60. try {
  61. if (hexStr.isEmpty) {
  62. throw ArgumentError('Hex string cannot be empty');
  63. }
  64. final normalizedHex = hexStr.startsWith('0x')
  65. ? hexStr.substring(2)
  66. : hexStr;
  67. if (!RegExp(r'^[0-9a-fA-F]+$').hasMatch(normalizedHex)) {
  68. throw FormatException('Invalid hex string format');
  69. }
  70. final bytes = hex.decode(normalizedHex.padLeft(
  71. normalizedHex.length + normalizedHex.length % 2,
  72. '0'
  73. ));
  74. final base64 = base64Encode(bytes);
  75. return urlSafe
  76. ? base64.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '')
  77. : base64;
  78. } on ArgumentError catch (e) {
  79. rethrow;
  80. } on FormatException catch (e) {
  81. rethrow;
  82. } catch (e) {
  83. throw Exception('Failed to convert hex to Base64: ${e.toString()}');
  84. }
  85. }
  86. /// 将 Base64 字符串转换为十六进制字符串
  87. ///
  88. /// [base64Str] 输入的 Base64 字符串
  89. /// [urlSafe] 输入是否是 URL 安全的 Base64 编码
  90. /// [withPrefix] 是否添加 "0x" 前缀
  91. ///
  92. /// 返回十六进制字符串或抛出异常
  93. String base64ToHex(String base64Str, {
  94. bool urlSafe = false,
  95. bool withPrefix = false,
  96. }) {
  97. try {
  98. if (base64Str.isEmpty) {
  99. throw ArgumentError('Base64 string cannot be empty');
  100. }
  101. String normalizedStr = base64Str;
  102. // 处理 URL 安全的 Base64
  103. if (urlSafe) {
  104. // 添加必要的填充字符
  105. final padding = '=' * ((4 - base64Str.length % 4) % 4);
  106. normalizedStr = base64Str
  107. .replaceAll('-', '+')
  108. .replaceAll('_', '/') + padding;
  109. }
  110. // 验证 Base64 字符串格式
  111. if (!RegExp(r'^[a-zA-Z0-9+/]*={0,2}$').hasMatch(normalizedStr)) {
  112. throw FormatException('Invalid Base64 string format');
  113. }
  114. // 解码为字节数组
  115. final bytes = base64Decode(normalizedStr);
  116. // 转换为十六进制
  117. final hexString = bytes.map((byte) {
  118. return byte.toRadixString(16).padLeft(2, '0');
  119. }).join('');
  120. return withPrefix ? '0x$hexString' : hexString;
  121. } on ArgumentError catch (e) {
  122. rethrow;
  123. } on FormatException catch (e) {
  124. rethrow;
  125. } catch (e) {
  126. throw Exception('Failed to convert Base64 to hex: ${e.toString()}');
  127. }
  128. }