I would like to parse binary file (from some old game) as on desktop as in browser. So, I should use abstract class, which can read binary data from array of bytes:
abstract class BinData {
int readByte();
String readNullString(){
var buffer = new StringBuffer();
int char;
do {
char = readByte();
if (char == 0){
break;
}
buffer.writeCharCode(char);
} while(true);
return buffer.toString();
}
}
Now I can implement my parser. For example:
class Parser {
BinData _data;
void load(BinData data){
...
}
}
For desktop console application I use dart:io RandomAccessFile:
class FileBinData extends BinData {
RandomAccessFile _file;
FileBinData.from(RandomAccessFile file){
this._file = file;
}
int readByte(){
return this._file.readByteSync();
}
}
For web application I have to use dart:html FileReader. However, this class has only Future-based API, which isn't compatible with my interface:
class WebFileBinData extends BinData {
File _file;
int _position = 0;
WebFileBinData.from(File file){
this._file = file;
}
int readByte(){
Blob blob = _file.slice(_position, _position + 1);
FileReader reader = new FileReader();
var future = reader.onLoad.map((e)=>reader.result).first
.then((e) { ... });
reader.readAsArrayBuffer(blob);
...
}
}
How can I solve it?
Your readByte()
should return Future<int>
instead of int
. You can return a Future
from a function/method even when it doesn't do any async operation (return new Future.value(5);
) but you can not return int
(or any non-Future value) from a function which executes async operations, at least not when the value should be returned as result of the async operation.
You also need to ensure to connect all async calls.
Future<int> readByte(){
return reader.onLoad.map((e)=>reader.result).first
.then((e) {
...
return reader.readAsArrayBuffer(blob);
});
** readNullString
Future<String> readNullString() {
var buffer = new StringBuffer();
int char;
return Future.doWhile(() {
return readByte().then((char) {
if (char == 0) {
return false; // end doWhile
}
buffer.writeCharCode(char);
return true; // continue doWhile
});
}).then((_) => buffer.toString()); // return function result
}