diff --git a/lib/archimedes_c_shim.dart b/lib/archimedes_c_shim.dart
new file mode 100644
index 0000000..b21a838
--- /dev/null
+++ b/lib/archimedes_c_shim.dart
@@ -0,0 +1,14 @@
+import 'dart:ffi';
+import 'package:archimedes_mobile_lib/dynloader.dart';
+import 'archimedes_mobile_lib_bindings_generated.dart';
+
+final _dylib = getArchimedesCLib();
+final ArchimedesMobileLibBindings _bindings =
+ ArchimedesMobileLibBindings(_dylib);
+
+int getImageData(Pointer frame, Pointer data) =>
+ _bindings.archimedes_get_image_data(frame, data);
+
+Pointer newFrame(
+ Pointer data, int dataLen, int w, int h, int depth) =>
+ _bindings.new_frame_from_data(data, dataLen, w, h, depth);
diff --git a/lib/archimedes_mobile_lib.dart b/lib/archimedes_mobile_lib.dart
index d1750a2..b85778a 100644
--- a/lib/archimedes_mobile_lib.dart
+++ b/lib/archimedes_mobile_lib.dart
@@ -4,43 +4,19 @@ import 'dart:io';
import 'dart:typed_data';
// import 'dart:isolate';
// import 'dart:ui';
+import 'package:archimedes_mobile_lib/archimedes_c_shim.dart';
+import 'package:archimedes_mobile_lib/dynloader.dart';
import "package:ffi/ffi.dart";
import "package:path/path.dart" show dirname, join;
import 'dart:io' show Platform;
import 'archimedes_mobile_lib_bindings_generated.dart';
-const String _libName = 'archimedes_mobile_lib';
-final here = dirname(Platform.script.path);
-final build = join(dirname(here), "build");
-
/// The dynamic library in which the symbols for [ArchimedesMobileLibBindings] can be found.
-final DynamicLibrary _dylib = () {
- if (Platform.isMacOS || Platform.isIOS) {
- return DynamicLibrary.open(join(build, '$_libName.framework', _libName));
- }
- if (Platform.isAndroid || Platform.isLinux) {
- return DynamicLibrary.open(join(build, 'lib$_libName.so'));
- }
- if (Platform.isWindows) {
- return DynamicLibrary.open(join('$_libName.dll'));
- }
- throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
-}();
-
-/// The bindings to the native functions in [_dylib].
-final ArchimedesMobileLibBindings _bindings =
- ArchimedesMobileLibBindings(_dylib);
-
-int getImageData(Pointer frame, Pointer data) =>
- _bindings.archimedes_get_image_data(frame, data);
-
-Pointer newFrame(
- Pointer data, int dataLen, int w, int h, int depth) =>
- _bindings.new_frame_from_data(data, dataLen, w, h, depth);
+final DynamicLibrary _dylib = getArchimedesCLib();
void main(List arguments) {
- final assets = join(dirname(here), "assets");
+ final assets = join(HERE.parent.path, "assets");
final testFrames = join(assets, "test", "frames");
final firstFrame = join(testFrames, "0001.png");
final f = File(firstFrame);
diff --git a/lib/dynloader.dart b/lib/dynloader.dart
new file mode 100644
index 0000000..d6a7499
--- /dev/null
+++ b/lib/dynloader.dart
@@ -0,0 +1,25 @@
+import 'dart:ffi';
+import 'dart:io';
+import "package:ffi/ffi.dart";
+import "package:path/path.dart" show dirname, join;
+import 'dart:io' show Platform;
+import 'archimedes_mobile_lib_bindings_generated.dart';
+
+const String _libName = 'archimedes_mobile_lib';
+final HERE = File(String.fromEnvironment("CURRENT_EXEC_DIR",
+ defaultValue: (File(Platform.script.path).parent.absolute.path)));
+final BUILD_DIR = File(join(HERE.path, "build"));
+
+DynamicLibrary getArchimedesCLib() {
+ if (Platform.isMacOS || Platform.isIOS) {
+ return DynamicLibrary.open(
+ join(BUILD_DIR.path, '$_libName.framework', _libName));
+ }
+ if (Platform.isAndroid || Platform.isLinux) {
+ return DynamicLibrary.open(join(BUILD_DIR.path, 'lib$_libName.so'));
+ }
+ if (Platform.isWindows) {
+ return DynamicLibrary.open(join(BUILD_DIR.path, '$_libName.dll'));
+ }
+ throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
+}
diff --git a/lib/util.dart b/lib/util.dart
new file mode 100644
index 0000000..174db4a
--- /dev/null
+++ b/lib/util.dart
@@ -0,0 +1,50 @@
+import 'dart:collection';
+import 'dart:ffi';
+import 'dart:io';
+import "package:ffi/ffi.dart";
+
+class Uint8FlexList extends ListBase {
+ final List _list = [];
+ Uint8FlexList();
+
+ late Pointer pointer;
+
+ @override
+ Uint8 operator [](int index) => _list[index];
+
+ set list(List l) {
+ _list.removeWhere((element) => true);
+ _list.addAll(l);
+ pointer = calloc(l.length);
+ _list.forEach((element) {
+ pointer[_list.indexOf(element)] = element as int;
+ });
+ }
+
+ @override
+ void operator []=(int index, Uint8 value) {
+ _list[index] = value;
+ pointer[index] = value as int;
+ }
+
+ @override
+ int get length => _list.length;
+
+ @override
+ set length(int newLength) {
+ throw Error();
+ }
+
+ static fromList(List l) {
+ final l2 = Uint8FlexList();
+ }
+}
+
+Pointer readUint8Ptr(File file) {
+ final l = file.readAsBytesSync().cast();
+ final dataPointer = calloc(l.length);
+ for (int i = 0; i < l.length; ++i) {
+ dataPointer[i] = l[i];
+ }
+ return dataPointer;
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 01213d4..a2722d2 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -8,6 +8,8 @@ environment:
flutter: '>=3.3.0'
dependencies:
+ test:
+ ffi:
flutter:
sdk: flutter
plugin_platform_interface: ^2.0.2
diff --git a/scripts/darttest.sh b/scripts/darttest.sh
new file mode 100755
index 0000000..2bc9e04
--- /dev/null
+++ b/scripts/darttest.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+SOURCE=${BASH_SOURCE[0]}
+while [ -L "$SOURCE" ]; do
+ DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
+ SOURCE=$(readlink "$SOURCE")
+ [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE
+done
+DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
+
+ROOT_DIR=$(realpath ${DIR}..)
+LIB_DIR=$(realpath ${DIR}/../lib)
+TEST_DIR=$(realpath ${DIR}/../tests)
+
+printf "\033c"
+
+dart --define=CURRENT_EXEC_DIR="${ROOT_DIR}" test ${TEST_DIR}
\ No newline at end of file
diff --git a/scripts/watch_darttest.sh b/scripts/watch_darttest.sh
new file mode 100755
index 0000000..a94202b
--- /dev/null
+++ b/scripts/watch_darttest.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+SOURCE=${BASH_SOURCE[0]}
+while [ -L "$SOURCE" ]; do
+ DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
+ SOURCE=$(readlink "$SOURCE")
+ [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE
+done
+DIR=$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)
+
+ROOT_DIR=$(realpath ${DIR}/..)
+LIB_DIR=$(realpath ${DIR}/../lib)
+TEST_DIR=$(realpath ${DIR}/../tests)
+
+cd ${ROOT_DIR} && find ${LIB_DIR} ${TEST_DIR} -iname '*.dart' | entr -r ${DIR}/darttest.sh
\ No newline at end of file
diff --git a/tests/main_test.dart b/tests/main_test.dart
new file mode 100644
index 0000000..5e7bfbb
--- /dev/null
+++ b/tests/main_test.dart
@@ -0,0 +1,27 @@
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:archimedes_mobile_lib/archimedes_c_shim.dart';
+import 'package:archimedes_mobile_lib/dynloader.dart';
+import 'package:archimedes_mobile_lib/util.dart';
+import 'package:ffi/ffi.dart';
+import 'package:test/test.dart';
+import "package:path/path.dart" show dirname, join;
+
+final assets = join(HERE.parent.path, "assets");
+final testFrames = join(assets, "test", "frames");
+final firstFrame = join(testFrames, "0001.png");
+
+void main() {
+ group('Unit Tests', () {
+ setUp(() {});
+
+ tearDown(() {
+ // Tear down code
+ });
+ test('newFrame', () {
+ Pointer frameData = readUint8Ptr(File(firstFrame));
+ // newFrame(frameData, fData.length, 768, 768, 1204);
+ });
+ });
+}