Last active
October 30, 2023 08:23
-
-
Save espresso3389/2007f5050130e12525b556ef8d4b7c3f to your computer and use it in GitHub Desktop.
Using icu from Dart/Flutter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:ffi'; | |
import 'dart:io'; | |
import 'package:ffi/ffi.dart'; | |
import 'package:unorm_dart/unorm_dart.dart' as unorm_dart; // fallback | |
String _getLibicuModuleName() { | |
if (Platform.isAndroid) { | |
return 'libicu.so'; | |
} else if (Platform.isWindows) { | |
return 'icuuc.dll'; | |
} | |
throw Exception('Unsupported platform'); | |
} | |
final _libicu = DynamicLibrary.open(_getLibicuModuleName()); | |
final _unorm2_getNFKCInstance = _libicu | |
.lookupFunction<Pointer Function(Pointer<Uint32>), Pointer Function(Pointer<Uint32>)>('unorm2_getNFKCInstance'); | |
final _unorm2_normalize = _libicu.lookupFunction< | |
Int32 Function(Pointer, Pointer<Utf16>, Int32, Pointer<Utf16>, Int32, Pointer<Uint32>), | |
int Function(Pointer, Pointer<Utf16>, int, Pointer<Utf16>, int, Pointer<Uint32>)>('unorm2_normalize'); | |
Pointer _getNFKCInstance() { | |
return using((arena) { | |
final err = arena.allocate<Uint32>(4); | |
err.value = 0; | |
final unorm = _unorm2_getNFKCInstance(err); | |
if (err.value > 0 || unorm.address == 0) { | |
throw Exception('unorm2_getNFKCInstance failed: ${err.value}'); | |
} | |
return unorm; | |
}); | |
} | |
bool? _haveIcu; | |
Pointer _unorm = Pointer.fromAddress(0); | |
String nfkc(String str) { | |
return using((arena) { | |
final err = arena.allocate<Uint32>(4); | |
try { | |
if (_haveIcu == null) { | |
_unorm = _getNFKCInstance(); | |
_haveIcu = true; | |
} | |
} catch (e) { | |
_haveIcu = false; | |
} | |
if (_haveIcu == false) { | |
return unorm_dart.nfkc(str); | |
} | |
final src = str.toNativeUtf16(allocator: arena); | |
err.value = 0; | |
final destLength = _unorm2_normalize(_unorm, src, -1, Pointer.fromAddress(0), 0, err); | |
// https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/utypes_8h_source.html#l00717 | |
const U_BUFFER_OVERFLOW_ERROR = 15; | |
if (err.value > 0 && err.value != U_BUFFER_OVERFLOW_ERROR) { | |
throw Exception('unorm2_normalize failed: ${err.value}'); | |
} | |
final dest = arena.allocate<Utf16>((destLength + 1) * 2); | |
err.value = 0; | |
_unorm2_normalize(_unorm, src, -1, dest, destLength + 1, err); | |
if (err.value > 0 && err.value != U_BUFFER_OVERFLOW_ERROR) { | |
throw Exception('unorm2_normalize failed: ${err.value}'); | |
} | |
return dest.toDartString(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment