Documenting Endian Behavior for ByteArray?


#1

Hi, so recently I ran into some major confusion when working with ByteArray. I had built a Haxe/OpenFL application that wrote a ByteArray to a file, and I found that I was unable to read the file from a separate Haxe app unless it was exported to the same target (i.e. CPP apps couldn’t read AIR-generated files, and AIR apps couldn’t read CPP generated files). I eventually solved this issue by manually setting the endian behavior to match everywhere in my code where I call new ByteArray() in both apps.

It’s my understanding now that this is expected behavior. Majority rules and the final verdict for endian behavior appears to be leaving it up to the platform to decide.

I think it would be a good idea to document this behavior somewhere so newcomers with a Flash background don’t run into “unexpected” expected behavior. As many developers migrate over to OpenFL from Flash, one might assume OpenFL’s ByteArray class is designed to behave universally across targets.

I think the API reference pages for the ByteArray or ByteArrayData classes might be good places for this to be explained, as this is where I was looking when I was trying to debug my issue (I eventually had to figure it by lucky guess, as similar issues people were having didn’t quite sound like mine). The Endian class could also probably use a modification in its description, as it describes how big endian is more common when communicating with servers, while little endian is more common with Intel architecture.

It seems probable that Flash defaulted to big endian in its API since it was designed to be used in a web environment. If this behavior is different with OpenFL for certain reasons I think it would be beneficial to officially document them so it is understood how files generated from ByteArray instances are not going to be cross-compatible with different targets unless endian order is manually enforced.

Anyway, would love to hear thoughts on this matter. If this is already documented somewhere and I missed it, a link would be appreciated as well!


#2

We used big-endian everywhere until OpenFL 6 over a year ago.

First, using big endian on little endian architectures was imposing an expensive performance hit when it was (in most cases) unnecessary.

Second, you mentioned the issue you had where an OpenFL application and an AIR-based application tried to read/write the same data, but had issues because the endianness was not the same. We kept running into this issue, but it was OpenFL and other system applications or C++ native extensions.

Endianness on native targets (C++, etc) by default use the system endianness. With the exception of PowerPC (which was last used in the Nintendo Wii, I believe) or in MIPS processors (used in some embedded systems) little-endian is the architecture of choice.

Endianness for web servers tends to prefer big-endian for “network byte order,” but interestingly, HTML5 typed arrays use the system byte-order and not network byte-order. It was for this reason that I felt we should prefer the system endianness, for performance, but also consistency with all the platforms we target (with the exception of our Flash target, which still uses big endian by default)

There’s a define called -Dopenfl-big-endian you can use on the command-line (<define name="openfl-big-endian" /> in project.xml) that reverses this behavior, I also wonder if Socket or XMLSocket should use big endian for network byte order, or if everything should be just be consistent.

I’d be very interested in knowing if Adobe AIR is big-endian always, or ever defaults to little-endian.

Regardless of what we do, I agree that documenting this behavior would be ideal.


#3

Thanks for the background information, it’s much appreciated! To be honest, your response itself would probably make perfect documentation information. If you look at the endian property of AS3’s ByteArray, you’ll read the following:

Changes or reads the byte order for the data; either Endian.BIG_ENDIAN or Endian.LITTLE_ENDIAN . The default value is BIG_ENDIAN.

So yes, big-endian should always be the case by default for AIR according to these docs. So additional information in openfl/utils/ByteArray.hx’s doc text would suffice in my opinion. (I’m happy to submit a PR if you think it’s worth it)

Overall I think the original behavior makes more sense in the Flash-ecosystem, where the programmer can expect the same behavior across every possible platform AIR/Flash can run on, even though it might not necessarily be the most widely used use case. But times are changing, so I don’t see the need to push for the old behavior

Also apologies for not being specific enough, but the AIR application I made is, in fact, OpenFL-based. So I understand that this can be an expected problem interopping with non-OpenFL applications, but I was experiencing the issue with separate OpenFL apps compiled to different targets. Currently Flash/AIR seem to be the easiest targets to debug with, so being able to load files generated from non-Flash builds saves a lot of time.


#4

I made improvements to our documentation, please take a look and see for yourself:

https://api.openfl.org/openfl/net/ObjectEncoding.html
https://api.openfl.org/openfl/utils/Endian.html
https://api.openfl.org/openfl/utils/ByteArray.html

We can make more improvements, as well, if you think we could use more description, thank you :slight_smile:

I also added a new defaultEndian property to ByteArray, so it can be changed at runtime

https://api.openfl.org/openfl/utils/ByteArray.html#defaultEndian


#5

Wow thanks! The ObjectEncoding documentation was a nice bonus too. This is exactly what I was looking for, so I really appreciate the help :smile: