Read sIndices as uint32's in binarywave.load.
[igor.git] / igor / binarywave.py
index a79c6be67cbc499f463d8b2c34a1390e6cfdde9b..e7f1282989650fffbe36fe8bde139a52b6e1daaa 100644 (file)
@@ -35,6 +35,9 @@ import numpy as _numpy
 from .struct import Structure as _Structure
 from .struct import Field as _Field
 from .util import assert_null as _assert_null
+from .util import byte_order as _byte_order
+from .util import need_to_reorder_bytes as _need_to_reorder_bytes
+from .util import checksum as _checksum
 
 
 # Numpy doesn't support complex integers by default, see
@@ -224,24 +227,7 @@ WaveHeader5 = _Structure(
 
 # End IGOR constants and typedefs from IgorBin.h
 
-# Begin functions from ReadWave.c
-
-def need_to_reorder_bytes(version):
-    # If the low order byte of the version field of the BinHeader
-    # structure is zero then the file is from a platform that uses
-    # different byte-ordering and therefore all data will need to be
-    # reordered.
-    return version & 0xFF == 0
-
-def byte_order(needToReorderBytes):
-    little_endian = _sys.byteorder == 'little'
-    if needToReorderBytes:
-        little_endian = not little_endian
-    if little_endian:
-        return '<'  # little-endian
-    return '>'  # big-endian    
-
-def version_structs(version, byte_order):
+def _version_structs(version, byte_order):
     if version == 1:
         bin = BinHeader1
         wave = WaveHeader2
@@ -265,20 +251,8 @@ def version_structs(version, byte_order):
     wave.set_byte_order(byte_order)
     return (bin, wave, checkSumSize)
 
-def checksum(buffer, byte_order, oldcksum, numbytes):
-    x = _numpy.ndarray(
-        (numbytes/2,), # 2 bytes to a short -- ignore trailing odd byte
-        dtype=_numpy.dtype(byte_order+'h'),
-        buffer=buffer)
-    oldcksum += x.sum()
-    if oldcksum > 2**31:  # fake the C implementation's int rollover
-        oldcksum %= 2**32
-        if oldcksum > 2**31:
-            oldcksum -= 2**31
-    return oldcksum & 0xffff
-
 # Translated from ReadWave()
-def loadibw(filename, strict=True):
+def load(filename, strict=True):
     if hasattr(filename, 'read'):
         f = filename  # filename is actually a stream object
     else:
@@ -286,23 +260,24 @@ def loadibw(filename, strict=True):
     try:
         BinHeaderCommon.set_byte_order('=')
         b = buffer(f.read(BinHeaderCommon.size))
-        version = BinHeaderCommon.unpack_dict_from(b)['version']
-        needToReorderBytes = need_to_reorder_bytes(version)
-        byteOrder = byte_order(needToReorderBytes)
-        
+        version = BinHeaderCommon.unpack_from(b)['version']
+        needToReorderBytes = _need_to_reorder_bytes(version)
+        byteOrder = _byte_order(needToReorderBytes)
+
         if needToReorderBytes:
             BinHeaderCommon.set_byte_order(byteOrder)
-            version = BinHeaderCommon.unpack_dict_from(b)['version']
-        bin_struct,wave_struct,checkSumSize = version_structs(version, byteOrder)
+            version = BinHeaderCommon.unpack_from(b)['version']
+        bin_struct,wave_struct,checkSumSize = _version_structs(
+            version, byteOrder)
 
         b = buffer(b + f.read(bin_struct.size + wave_struct.size - BinHeaderCommon.size))
-        c = checksum(b, byteOrder, 0, checkSumSize)
+        c = _checksum(b, byteOrder, 0, checkSumSize)
         if c != 0:
             raise ValueError(
                 ('This does not appear to be a valid Igor binary wave file.  '
                  'Error in checksum: should be 0, is {}.').format(c))
-        bin_info = bin_struct.unpack_dict_from(b)
-        wave_info = wave_struct.unpack_dict_from(b, offset=bin_struct.size)
+        bin_info = bin_struct.unpack_from(b)
+        wave_info = wave_struct.unpack_from(b, offset=bin_struct.size)
         if version in [1,2,3]:
             tail = 16  # 16 = size of wData field in WaveHeader2 structure
             waveDataSize = bin_info['wfmSize'] - wave_struct.size
@@ -407,20 +382,29 @@ def loadibw(filename, strict=True):
                 labels = str(f.read(size)).split(chr(0)) # split null-delimited strings
                 bin_info['dimLabels'].append([L for L in labels if len(L) > 0])
             if wave_info['type'] == 0:  # text wave
-                bin_info['sIndices'] = f.read(bin_info['sIndicesSize'])
+                sIndices_data = f.read(bin_info['sIndicesSize'])
+                sIndices_count = bin_info['sIndicesSize']/4
+                bin_info['sIndices'] = _numpy.ndarray(
+                    shape=(sIndices_count,),
+                    dtype=_numpy.dtype(
+                        _numpy.uint32()).newbyteorder(byteOrder),
+                    buffer=sIndices_data,
+                    order='F',
+                    )
 
         if wave_info['type'] == 0:  # text wave
             # use sIndices to split data into strings
             strings = []
             start = 0
-            for i,string_index in enumerate(bin_info['sIndices']):
-                offset = ord(string_index)
+            for i,offset in enumerate(bin_info['sIndices']):
                 if offset > start:
                     string = data[start:offset]
                     strings.append(''.join(chr(x) for x in string))
                     start = offset
+                elif offset == start:
+                    strings.append('')
                 else:
-                    assert offset == 0, offset
+                    raise ValueError((offset, bin_info['sIndices']))
             data = _numpy.array(strings)
             shape = [n for n in wave_info['nDim'] if n > 0] or (0,)
             data.reshape(shape)
@@ -431,5 +415,5 @@ def loadibw(filename, strict=True):
     return data, bin_info, wave_info
 
 
-def saveibw(filename):
+def save(filename):
     raise NotImplementedError