[Android] Possible bug in ByteArray.readFloat()?

I’ve found out that sometimes when i read a file that contains byte array data, the readFloat method of Android’s ByteArray class reads either a really big or minus that.

When i further investigated this, i saw that the bytes are written backwards!

2 things to notice:

  1. when i target HTML5 / Flash it works as expected. so this is probably a bug in Android’s code.

  2. This PATCH function fixed the problem:

    public static function readFloat(ba:ByteArray):Float
    {
    #if android
    return readReversedFloat(ba);
    #else
    return ba.readFloat();
    #end
    }
    private static function readReversedFloat(ba:ByteArray):Float
    {
    var temp:ByteArray = new ByteArray();
    var b1:ByteArray = new ByteArray();
    var b2:ByteArray = new ByteArray();
    var b3:ByteArray = new ByteArray();
    var b4:ByteArray = new ByteArray();
    ba.readBytes(b1, 0, 1);
    ba.readBytes(b2, 0, 1);
    ba.readBytes(b3, 0, 1);
    ba.readBytes(b4, 0, 1);

     temp.writeBytes(b4);
     temp.writeBytes(b3);
     temp.writeBytes(b2);
     temp.writeBytes(b1);
    
     temp.position = 0;
     var resp:Float = temp.readFloat();
     return resp;
    

    }

This fixed the issue but its not very efficient in runtime…
Should i report a bug?

Try setting the endian value of the ByteArray, perhaps it defaults to the wrong endianness?

Further investigation:

  1. changing endian of the byte array did not fix this issue.

  2. furthermore, all the other reads are OK. Only readFloat is acting weird… (readInt / readBytes etc… are OK)

  3. Maybe it has to do with the fact im reading the ByteArray file with Assets.getBytes() ?

Looking at the source, it appears we are using the Haxe getFloat method of Bytes, where in many other functions we use our own code, and respect endianness:

https://github.com/openfl/lime/blob/master/lime/utils/ByteArray.hx

Perhaps the getFloat method works only with a certain kind of endianness, or we need to do something else

1 Like

@singmajesty do you think i need to report this as a bug?

Does readFloat work for you on the desktop? Is there anywhere other than Android where it fails, too?

Did not try that. Will do that soon and update.

Finally, I had some time to further investigate the issue, here are some of my personal conclusions:

  1. In my tests, this happens only with readFloat().
  2. This happens when i load an external ByteArray (Written in a flash application for example)

I looked into openfl.utils.ByteArrayData’s method readFloat, it looks like this (there’s no notice to Endian…) :

     public function readFloat ():Float {
        if (position + 4 > __length) {
            throw new EOFError ();
        }
        position += 4;
        return getFloat (position - 4);            
    }

While readInt takes notice of endian:

     public function readInt ():Int {
        var ch1 = readUnsignedByte ();
        var ch2 = readUnsignedByte ();
        var ch3 = readUnsignedByte ();
        var ch4 = readUnsignedByte ();            
        if (endian == LITTLE_ENDIAN) {                
            return (ch4 << 24) | (ch3 << 16) | (ch2 << 8) | ch1;                
        } else {                
            return (ch1 << 24) | (ch2 << 16) | (ch3 << 8) | ch4;                
        }            
    }

and i compared writeFloat of as3 and openfl, openfl reads and writes float as LITTLE_ENDIAN, changing the endian value of the ByteArray does not effect the read value.

Am I missing something? how do i make readFloat take note of the endian value?

Just came across this issue as well with the HTML5 target and looking at the docs for haxe Bytes it says:

getFloat (pos:Int):Float
Returns the IEEE single precision value at given position (in low endian encoding). Result is unspecified if reading outside of the bounds

So it using haxe Bytes does look like it returns in low endian format all the time and this causes an error when using the big-endian format.

Taking a quick look now at what can be done to fix it. Will keep you posted on any outcome.

Do you think it would be similar to the readInt code, but with a Float return type? Perhaps we can use the current code if the endianness matches, or otherwise fall to more complex code like readInt does

I think I found another bug in readFloat() in android and next.
My code runs fine in windows (next/legacy), flash and android legacy. But when I use next in android, as soon as my code tries reading a float from a bytearray the app crashes. Im using little endian. Does next use another implementation of bytearray?


The crash stack is:

01-20 01:51:15.810 276 276 F DEBUG : #00 pc 00abbf20 /data/app/uy.gg.EntitySystemBase-1/lib/arm/libApplicationMain.so (__hxcpp_align_get_float32(unsigned char*, int)+24)

01-20 01:51:15.810 276 276 F DEBUG : #01 pc 00abbff0 /data/app/uy.gg.EntitySystemBase-1/lib/arm/libApplicationMain.so (__hxcpp_memory_get_float(Array, int)+52)

01-20 01:51:15.810 276 276 F DEBUG : #02 pc 00abe01c /data/app/uy.gg.EntitySystemBase-1/lib/arm/libApplicationMain.so (openfl::utils::ByteArrayData_obj::readFloat()+700)

Right now we use haxe.io.Bytes getFloat for this, but perhaps we need to be more manual about it, similar to the readInt implementation

1 Like

The good news is that I made my code run the bad news is that I dont know what is going on and the solution is more a hack.
So at least in my case the bytearray is created in an adobe air app and then loaded by openfl.
I made a simple example in openfl writing and reading floats on a bytearray and it work, so I try writing the same bytes generated by flash and reading them as floats and it work again.
So I made a buffer, I write the bytes to the buffer and read them as floats.

           buffer.position = 0;
                    for (i in 0...numberFloatReads*4) 
                    {
                        buffer.writeByte(data.readUnsignedByte());
                    }
                    buffer.position = 0;
                   buffer.readFloat();....

So Im thinking that the error may come from some inconsistency between how Assets.getBytes imports the data and how openfl is using it. Still dont know why in windows it dosent crash, maybe the cast is diferent on android?

Still the problem with endian remains, luckly I have my data in little endian, but apparently you cant use big endian and floats without doing a little hack.