From 04ff988195aea1c2115aa64b095f5730f5c285fe Mon Sep 17 00:00:00 2001
From: Jasm Sison <jasm.sison@gmail.com>
Date: Wed, 4 Sep 2019 17:22:25 +0200
Subject: [PATCH 1/3] added utf8 support

---
 lib/src/box.dart         | 10 +++++-----
 lib/src/common.dart      |  2 +-
 lib/src/ffi/cstring.dart | 32 ++++++++++++++++++++++----------
 pubspec.yaml             |  3 ++-
 test/test.dart           | 12 +++++++++---
 5 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/lib/src/box.dart b/lib/src/box.dart
index 32e9776a1..8f2e6164e 100644
--- a/lib/src/box.dart
+++ b/lib/src/box.dart
@@ -125,25 +125,25 @@ class Box<T> {
         }
 
         // transform flatbuffers byte array into memory area for C, with a length of a multiple of four
-        Pointer<Uint8> bufferPtr = allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4);
+        Pointer<Uint8> bufferPtr = Pointer<Uint8>.allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4);
         for(int i = 0; i < buffer.length; ++i)
             bufferPtr.elementAt(i).store(buffer[i] as int);
 
         // put object into box and free the buffer
-        checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], fromAddress(bufferPtr.address), buffer.length, putMode));
+        checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], Pointer<Void>.fromAddress(bufferPtr.address), buffer.length, putMode));
         bufferPtr.free();
     }
 
     getById(int id) {
-        Pointer<Pointer<Void>> dataPtr = allocate();
-        Pointer<Int32> sizePtr = allocate();
+        Pointer<Pointer<Void>> dataPtr = Pointer<Pointer<Void>>.allocate();
+        Pointer<Int32> sizePtr = Pointer<Int32>.allocate();
 
         // get element with specified id from database
         Pointer<Void> txn = bindings.obx_txn_read(_store.ptr);
         check(txn != null && txn.address != 0);
         checkObx(bindings.obx_box_get(_objectboxBox, id, dataPtr, sizePtr));
         checkObx(bindings.obx_txn_close(txn));
-        Pointer<Uint8> data = fromAddress(dataPtr.load<Pointer<Void>>().address);
+        Pointer<Uint8> data = Pointer<Uint8>.fromAddress(dataPtr.load<Pointer<Void>>().address);
         var size = sizePtr.load<int>();
 
         // transform bytes from memory to Dart byte list
diff --git a/lib/src/common.dart b/lib/src/common.dart
index 36d2217a0..3dbe50520 100644
--- a/lib/src/common.dart
+++ b/lib/src/common.dart
@@ -5,7 +5,7 @@ import "ffi/cstring.dart";
 
 class Common {
     static List<int> version() {
-        Pointer<Int32> majorPtr = allocate(),  minorPtr = allocate(), patchPtr = allocate();
+        Pointer<Int32> majorPtr = Pointer<Int32>.allocate(), minorPtr = Pointer<Int32>.allocate(), patchPtr = Pointer<Int32>.allocate();
         bindings.obx_version(majorPtr, minorPtr, patchPtr);
         var ret = [majorPtr.load<int>(), minorPtr.load<int>(), patchPtr.load<int>()];
         majorPtr.free();
diff --git a/lib/src/ffi/cstring.dart b/lib/src/ffi/cstring.dart
index 6f04cdc84..2a637845f 100644
--- a/lib/src/ffi/cstring.dart
+++ b/lib/src/ffi/cstring.dart
@@ -1,24 +1,36 @@
 import "dart:ffi";
+import "dart:typed_data";
+import "package:utf/src/utf8.dart";
+import "package:utf/src/utf16.dart";
 
+// TODO check if revamp structs are relevant (https://github.com/dart-lang/sdk/issues/37229)
 // wrapper for a null-terminated array of characters in memory ("c-style string")
 class CString {
     Pointer<Uint8> _ptr;
 
-    CString(String dartStr) {                                   // if this constructor is used, ".free" needs to be called on this instance
-        _ptr = allocate(count: dartStr.length + 1);
-        for(int i = 0; i < dartStr.length; ++i)
-            _ptr.elementAt(i).store(dartStr.codeUnitAt(i));
-        _ptr.elementAt(dartStr.length).store(0);
+    // if this constructor is used, ".free" needs to be called on this instance
+    CString(String dartStr) {
+        List<int> ints = encodeUtf8(dartStr);
+        var utf8Str = Uint8List.fromList(ints);
+        _ptr = Pointer<Uint8>.allocate(count: utf8Str.length + 1);
+        for(int i = 0; i < utf8Str.length; ++i)
+            _ptr.elementAt(i).store(utf8Str.elementAt(i));
+        _ptr.elementAt(utf8Str.length).store(0);
     }
 
     CString.fromPtr(this._ptr);
 
     String get val {
-        String ret = "", c;
-        int i = 0;
-        while((c = String.fromCharCode(_ptr.elementAt(i++).load<int>())).codeUnitAt(0) != 0)          // TODO: unicode support
-            ret += c;
-        return ret;
+        List<int> utf8CodePoints = new List<int>();
+
+        int element;
+        
+        for (int i=0; element != 0; i++) {
+	    element = _ptr.elementAt(i).load<int>();
+	    utf8CodePoints.add(element);
+        }
+
+        return decodeUtf8(utf8CodePoints);
     }
 
     String toString() => val;
diff --git a/pubspec.yaml b/pubspec.yaml
index e53166272..ff901d14e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,8 +1,9 @@
 name: objectbox
-version: 0.0.1
+version: 0.0.2
 description: >-
   ObjectBox binding for Dart.
 environment:
   sdk: '>=2.2.2 <3.0.0'
 dependencies:
   flat_buffers: ^1.11.0
+  utf: ^0.9.0
diff --git a/test/test.dart b/test/test.dart
index 70068f746..6507bf1a2 100644
--- a/test/test.dart
+++ b/test/test.dart
@@ -1,4 +1,5 @@
 import "../lib/objectbox.dart";
+import "package:utf/src/utf8.dart";
 
 @Entity(id: 1, uid: 1)
 class Note {
@@ -17,11 +18,16 @@ class Note {
 main() {
     var store = Store([Note]);
     var box = Box<Note>(store);
+    insertNote(box, decodeUtf8([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]));
+    insertNote(box, decodeUtf8([228, 189, 160, 229, 165, 189, 228, 184, 150, 231, 149, 140, 33]));
+    insertNote(box, decodeUtf8([65, 104, 111, 106, 32, 115, 118, 196, 155, 116, 101, 33]));
+    store.close();
+}
 
-    var note = Note.construct("Hello");
+insertNote(Box<Note> box, String str) {
+    var note = Note.construct(str);
     box.put(note);
+
     print("new note got id ${note.id}");
     print("refetched note: ${box.getById(note.id)}");
-    
-    store.close();
 }

From 9026bc466f5a06e058d4c62ff8d17dc64bb52b4f Mon Sep 17 00:00:00 2001
From: Jasm Sison <jasm.sison@gmail.com>
Date: Thu, 5 Sep 2019 15:31:02 +0200
Subject: [PATCH 2/3] I tried explicitly casting with `x as Uint8` and `(Uint)
 x` this triggered some weird compiler errors. Then I tried this without
 explicitly casting, evidently there's some type polymorphism going on, or
 some casting by the compiler.

In any case, the Uint8List has been removed.
---
 lib/src/ffi/cstring.dart | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/src/ffi/cstring.dart b/lib/src/ffi/cstring.dart
index 2a637845f..898f26e4b 100644
--- a/lib/src/ffi/cstring.dart
+++ b/lib/src/ffi/cstring.dart
@@ -10,12 +10,12 @@ class CString {
 
     // if this constructor is used, ".free" needs to be called on this instance
     CString(String dartStr) {
-        List<int> ints = encodeUtf8(dartStr);
-        var utf8Str = Uint8List.fromList(ints);
-        _ptr = Pointer<Uint8>.allocate(count: utf8Str.length + 1);
-        for(int i = 0; i < utf8Str.length; ++i)
-            _ptr.elementAt(i).store(utf8Str.elementAt(i));
-        _ptr.elementAt(utf8Str.length).store(0);
+        final ints = encodeUtf8(dartStr);
+        _ptr = Pointer<Uint8>.allocate(count: ints.length + 1);
+        for(int i = 0; i < ints.length; ++i) {
+            _ptr.elementAt(i).store(ints.elementAt(i));
+        }
+        _ptr.elementAt(ints.length).store(0);
     }
 
     CString.fromPtr(this._ptr);

From c77e1b8414c68e7011744ec7ad0059ed79b8dcb0 Mon Sep 17 00:00:00 2001
From: Jasm Sison <jasm.sison@gmail.com>
Date: Thu, 5 Sep 2019 15:52:37 +0200
Subject: [PATCH 3/3] Maintain support for 2.4's ffi

TODO Revert and test this commit  when 2.5 is released as stable
---
 lib/src/box.dart    | 10 +++++-----
 lib/src/common.dart |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/src/box.dart b/lib/src/box.dart
index 8f2e6164e..32e9776a1 100644
--- a/lib/src/box.dart
+++ b/lib/src/box.dart
@@ -125,25 +125,25 @@ class Box<T> {
         }
 
         // transform flatbuffers byte array into memory area for C, with a length of a multiple of four
-        Pointer<Uint8> bufferPtr = Pointer<Uint8>.allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4);
+        Pointer<Uint8> bufferPtr = allocate(count: ((buffer.length + 3.0) / 4.0).toInt() * 4);
         for(int i = 0; i < buffer.length; ++i)
             bufferPtr.elementAt(i).store(buffer[i] as int);
 
         // put object into box and free the buffer
-        checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], Pointer<Void>.fromAddress(bufferPtr.address), buffer.length, putMode));
+        checkObx(bindings.obx_box_put(_objectboxBox, propVals[_idPropIdx]["value"], fromAddress(bufferPtr.address), buffer.length, putMode));
         bufferPtr.free();
     }
 
     getById(int id) {
-        Pointer<Pointer<Void>> dataPtr = Pointer<Pointer<Void>>.allocate();
-        Pointer<Int32> sizePtr = Pointer<Int32>.allocate();
+        Pointer<Pointer<Void>> dataPtr = allocate();
+        Pointer<Int32> sizePtr = allocate();
 
         // get element with specified id from database
         Pointer<Void> txn = bindings.obx_txn_read(_store.ptr);
         check(txn != null && txn.address != 0);
         checkObx(bindings.obx_box_get(_objectboxBox, id, dataPtr, sizePtr));
         checkObx(bindings.obx_txn_close(txn));
-        Pointer<Uint8> data = Pointer<Uint8>.fromAddress(dataPtr.load<Pointer<Void>>().address);
+        Pointer<Uint8> data = fromAddress(dataPtr.load<Pointer<Void>>().address);
         var size = sizePtr.load<int>();
 
         // transform bytes from memory to Dart byte list
diff --git a/lib/src/common.dart b/lib/src/common.dart
index 3dbe50520..36d2217a0 100644
--- a/lib/src/common.dart
+++ b/lib/src/common.dart
@@ -5,7 +5,7 @@ import "ffi/cstring.dart";
 
 class Common {
     static List<int> version() {
-        Pointer<Int32> majorPtr = Pointer<Int32>.allocate(), minorPtr = Pointer<Int32>.allocate(), patchPtr = Pointer<Int32>.allocate();
+        Pointer<Int32> majorPtr = allocate(),  minorPtr = allocate(), patchPtr = allocate();
         bindings.obx_version(majorPtr, minorPtr, patchPtr);
         var ret = [majorPtr.load<int>(), minorPtr.load<int>(), patchPtr.load<int>()];
         majorPtr.free();