Skip to content

Instantly share code, notes, and snippets.

@mraleph
Last active March 9, 2021 17:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mraleph/4eb5ccbb38904075141e to your computer and use it in GitHub Desktop.
Save mraleph/4eb5ccbb38904075141e to your computer and use it in GitHub Desktop.
manual big endian conversion in Dart
library writer;
import 'dart:typed_data';
/// Writer wraps a fixed size Uint8List and writes values into it using
/// big-endian byte order.
class Writer {
/// Output buffer.
final Uint8List out;
/// Current position within [out].
var position = 0;
Writer._create(this.out);
factory Writer(size) {
final out = new Uint8List(size);
if (Endianness.HOST_ENDIAN == Endianness.LITTLE_ENDIAN) {
return new _WriterForLEHost._create(out);
} else {
return new _WriterForBEHost._create(out);
}
}
writeFloat64(double v);
writeFloat32(double v);
writeInt32(int v) {
out[position + 3] = v;
out[position + 2] = (v >> 8);
out[position + 1] = (v >> 16);
out[position + 0] = (v >> 24);
position += 4;
}
writeInt16(int v) {
out[position + 1] = v;
out[position + 0] = (v >> 8);
position += 2;
}
writeInt8(int v) {
out[position] = v;
position++;
}
writeString(String str) {
out.setAll(position, str.codeUnits);
position += str.codeUnits.length;
}
}
/// Lists used for data convertion (alias each other).
final Uint8List _convU8 = new Uint8List(8);
final Float32List _convF32 = new Float32List.view(_convU8.buffer);
final Float64List _convF64 = new Float64List.view(_convU8.buffer);
/// Writer used on little-endian host.
class _WriterForLEHost extends Writer {
_WriterForLEHost._create(out) : super._create(out);
writeFloat64(double v) {
_convF64[0] = v;
out[position + 7] = _convU8[0];
out[position + 6] = _convU8[1];
out[position + 5] = _convU8[2];
out[position + 4] = _convU8[3];
out[position + 3] = _convU8[4];
out[position + 2] = _convU8[5];
out[position + 1] = _convU8[6];
out[position + 0] = _convU8[7];
position += 8;
}
writeFloat32(double v) {
_convF32[0] = v;
out[position + 3] = _convU8[0];
out[position + 2] = _convU8[1];
out[position + 1] = _convU8[2];
out[position + 0] = _convU8[3];
position += 4;
}
}
/// Writer used on the big-endian host.
class _WriterForBEHost extends Writer {
_WriterForBEHost._create(out) : super._create(out);
writeFloat64(double v) {
_convF64[0] = v;
out[position + 0] = _convU8[0];
out[position + 1] = _convU8[1];
out[position + 2] = _convU8[2];
out[position + 3] = _convU8[3];
out[position + 4] = _convU8[4];
out[position + 5] = _convU8[5];
out[position + 6] = _convU8[6];
out[position + 7] = _convU8[7];
position += 8;
}
writeFloat32(double v) {
_convF32[0] = v;
out[position + 0] = _convU8[0];
out[position + 1] = _convU8[1];
out[position + 2] = _convU8[2];
out[position + 3] = _convU8[3];
position += 4;
}
}
@devfelipereis
Copy link

devfelipereis commented Mar 8, 2021

I'm trying to convert this hex "F8424660" to timestamp but without success. Can you give me some advice?
The expected value is: 1615217400

In fact I need to convert some hex values to int, float and so on. Using little endian.
I'm a beginner in dart and I'm little confused on how to do this.

@mraleph
Copy link
Author

mraleph commented Mar 8, 2021

@devfelipereis Well, good answer to your question depends on where and how you get this hex from. Are you getting hex value or are you getting a sequence of bytes from somewhere?

Well, 1615217400 is 604642f8 in hex, so F8424660 is a big endian version of this. You can reverse byte order manually, e.g.

  final value = int.parse('F8424660', radix: 16);
  final timestamp = (value & 0xFF) << 24 | (value & 0xFF00) << 8 | (value & 0xFF0000) >> 8 | (value & 0xFF000000) >> 24;
  print(timestamp); // => 1615217400

There is nothing too Dart specific here.

@devfelipereis
Copy link

@mraleph I'm getting something like this:

534D627480650300A201F84246600000F0420000F2420000F4420000803F000000400000404000007A4400002041005043470050C3466666663FCDCC4C3F3333333F00007042333333333333E33F9A9999999999D93F40016001200100E700E700E700E700E700E7B803BD03B30332

this data comes from a bluetooth device. Then I need to break this in parts and extract some informations.

Timestamp is in the position 20-28. Some values are float, some are int. What I need to do is get this values and parse to the correct type.

What should I study do understand how this conversions work? Thank you!

@mraleph
Copy link
Author

mraleph commented Mar 9, 2021

If you want to understand fundamentals then you should study how different types are represented in memory and have a grasp of things like big/little endian byte orders.

For parsing you can use ByteData class, it allows you to extract specific types from a sequence of bytes.

If data arrives to you as hex string you can convert it into a List<int> using hex codec from package:convert, after that you can create ByteData from it, e.g.

import 'dart:typed_data';
import 'package:convert/convert.dart';

void parse(String s) {
  // Convert hex from the given string to a sequence of bytes (first two characters become first byte and so on). 
  final bd = ByteData.sublistView(Uint8List.fromList(hex.decode(s)));
  print(bd.getInt32(10, Endian.little)); // print timestamp (should print  1615217400)
}

void main() {
  
 parse('534D627480650300A201F84246600000F0420000F2420000F4420000803F000000400000404000007A4400002041005043470050C3466666663FCDCC4C3F3333333F00007042333333333333E33F9A9999999999D93F40016001200100E700E700E700E700E700E7B803BD03B30332');
}

@devfelipereis
Copy link

@mraleph thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment