How do I create a floating point value?

0 votes
asked Mar 14, 2017 in Python by webbnh (160 points)
edited Mar 14, 2017 by webbnh

The file that I'm parsing consists of multiple records of various types.  The records have a standard header (which makes it straightforward to determine the type), and a standard trailer.  The fields in between, however, are XOR-encoded, with makes things more complicated.  I've resorted to defining custom elements for strings, binary data, and integers, and things have gone pretty well.  (Nevertheless, if there's a better approach, I would very much like to hear about it!)

However, the record that I'm working on now has fields which are floating point numbers (little-endian, eight bytes).  Given the apparently limited classes and methods which are available to scripted elements (I'm working in Python), how can I construct the value to be passed to value.setFloat() from the bytes I get from byteView.readByte()?



OK, I've discovered that I can import the struct package, which I think will close the gap.  However, now I'm getting an error:

Python: 'TypeError: in method 'Value_setFloat', argument 2 of type 'double''

The documentation suggests that value.setFloat() should accept a double (I was presuming that if I passed it a single-precision float, that the argument would be silently promoted). Is the documentation wrong, or is it just me?


[Edited, again]

Apparently the problem is that Python has a poor error message in this instance.  The issue is that struct.unpack() returns a tuple which, if passed directly to value.setFloat() causes a type error (as it presumably should).  However, it would have been nice if the error message had mentioned the type received as well as the type expected.

So, I believe the answer to my original question is code like the following:

def parseByteRange(element, byteView, bitPos, bitLength, results):
    # this method parses data starting at bitPos, bitLength bits are remaining
    """parseByteRange method"""

    bytePos = bitPos / 8
    byteLength = bitLength / 8
    byteString = ""

    xorMask = getXorMask(results)

    for i in range(byteLength):
        byteRead = byteView.readByte(bytePos)
        byteRead ^= xorMask
        byteString += chr(byteRead)
        bytePos += 1

    # how many bytes were processed?
    processedBytes = byteLength
    iteration = 0
    floatValue = (0.0,)

    if byteLength == 4 :
        floatValue = struct.unpack('<f', byteString)
    elif byteLength == 8 :
        floatValue = struct.unpack('<d', byteString)
    else :
        logVerboseMessage("Unexpected float length: %d" % byteLength)

    # create and set new value

    value = NumberValue()

    results.addElement(element, processedBytes, iteration, value)

    # return number of processed bytes
    return processedBytes

(If anyone has any feedback on this, I would appreciate hearing it! -- Thanks!)

1 Answer

0 votes
answered Mar 14, 2017 by webbnh (160 points)
I answered my own question in the last edit above.  Sorry for the bother, all.

[Strangely, the server wouldn't let me post my last edit above as an answer...]