-# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2010-2012 W. Trevor King <wking@tremily.us>
#
-# This file is part of Hooke.
+# This file is part of igor.
#
-# Hooke is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# igor is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
#
-# Hooke is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
-# Public License for more details.
+# igor is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with Hooke. If not, see
-# <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Lesser General Public License
+# along with igor. If not, see <http://www.gnu.org/licenses/>.
"Read IGOR Binary Wave files into Numpy arrays."
class StaticStringField (_DynamicField):
_null_terminated = False
_array_size_field = None
+ def __init__(self, *args, **kwargs):
+ if 'array' not in kwargs:
+ kwargs['array'] = True
+ super(StaticStringField, self).__init__(*args, **kwargs)
+
def post_unpack(self, parents, data):
wave_structure = parents[-1]
wave_data = self._get_structure_data(parents, data, wave_structure)
wave_data[self.name] = d
def _normalize_string(self, d):
- if hasattr(d, 'tostring'):
+ if isinstance(d, bytes):
+ pass
+ elif hasattr(d, 'tobytes'):
+ d = d.tobytes()
+ elif hasattr(d, 'tostring'): # Python 2 compatibility
d = d.tostring()
else:
- d = ''.join(d)
+ d = b''.join(d)
if self._array_size_field:
start = 0
strings = []
if end > start:
strings.append(d[start:end])
if self._null_terminated:
- strings[-1] = strings[-1].split('\x00', 1)[0]
+ strings[-1] = strings[-1].split(b'\x00', 1)[0]
start = end
elif self._null_terminated:
- d = d.split('\x00', 1)[0]
+ d = d.split(b'\x00', 1)[0]
return d
_Field('l', 'formulaSize', help='The size of the dependency formula, if any.'),
_Field('l', 'noteSize', help='The size of the note text.'),
_Field('l', 'dataEUnitsSize', help='The size of optional extended data units.'),
- _Field('l', 'dimEUnitsSize', help='The size of optional extended dimension units.', count=MAXDIMS),
- _Field('l', 'dimLabelsSize', help='The size of optional dimension labels.', count=MAXDIMS),
+ _Field('l', 'dimEUnitsSize', help='The size of optional extended dimension units.', count=MAXDIMS, array=True),
+ _Field('l', 'dimLabelsSize', help='The size of optional dimension labels.', count=MAXDIMS, array=True),
_Field('l', 'sIndicesSize', help='The size of string indicies if this is a text wave.'),
_Field('l', 'optionsSize1', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('l', 'optionsSize2', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('h', 'whVersion', default=0, help='Write 0. Ignore on read.'),
_Field('h', 'srcFldr', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('P', 'fileName', default=0, help='Used in memory only. Write zero. Ignore on read.'),
- _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1),
- _Field('c', 'xUnits', default=0, help='Natural x-axis units go here - null if none.', count=MAX_UNIT_CHARS+1),
+ _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1, array=True),
+ _Field('c', 'xUnits', default=0, help='Natural x-axis units go here - null if none.', count=MAX_UNIT_CHARS+1, array=True),
_Field('l', 'npnts', help='Number of data points in wave.'),
_Field('h', 'aModified', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('d', 'hsA', help='X value for point p = hsA*p + hsB'),
_Field('P', 'formula', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('l', 'depID', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('L', 'creationDate', help='DateTime of creation. Not used in version 1 files.'),
- _Field('c', 'wUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=2),
+ _Field('c', 'wUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=2, array=True),
_Field('L', 'modDate', help='DateTime of last modification.'),
_Field('P', 'waveNoteH', help='Used in memory only. Write zero. Ignore on read.'),
])
_Field('l', 'npnts', help='Total number of points (multiply dimensions up to first zero).'),
_Field('h', 'type', help='See types (e.g. NT_FP64) above. Zero for text waves.'),
_Field('h', 'dLock', default=0, help='Reserved. Write zero. Ignore on read.'),
- _Field('c', 'whpad1', default=0, help='Reserved. Write zero. Ignore on read.', count=6),
+ _Field('c', 'whpad1', default=0, help='Reserved. Write zero. Ignore on read.', count=6, array=True),
_Field('h', 'whVersion', default=1, help='Write 1. Ignore on read.'),
NullStaticStringField('c', 'bname', help='Name of wave plus trailing null.', count=MAX_WAVE_NAME5+1),
_Field('l', 'whpad2', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('P', 'dFolder', default=0, help='Used in memory only. Write zero. Ignore on read.'),
# Dimensioning info. [0] == rows, [1] == cols etc
- _Field('l', 'nDim', help='Number of of items in a dimension -- 0 means no data.', count=MAXDIMS),
- _Field('d', 'sfA', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS),
- _Field('d', 'sfB', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS),
+ _Field('l', 'nDim', help='Number of of items in a dimension -- 0 means no data.', count=MAXDIMS, array=True),
+ _Field('d', 'sfA', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS, array=True),
+ _Field('d', 'sfB', help='Index value for element e of dimension d = sfA[d]*e + sfB[d].', count=MAXDIMS, array=True),
# SI units
- _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1),
- _Field('c', 'dimUnits', default=0, help='Natural dimension units go here - null if none.', count=(MAXDIMS, MAX_UNIT_CHARS+1)),
+ _Field('c', 'dataUnits', default=0, help='Natural data units go here - null if none.', count=MAX_UNIT_CHARS+1, array=True),
+ _Field('c', 'dimUnits', default=0, help='Natural dimension units go here - null if none.', count=(MAXDIMS, MAX_UNIT_CHARS+1), array=True),
_Field('h', 'fsValid', help='TRUE if full scale values have meaning.'),
_Field('h', 'whpad3', default=0, help='Reserved. Write zero. Ignore on read.'),
_Field('d', 'topFullScale', help='The max and max full scale value for wave'), # sic, probably "max and min"
_Field('d', 'botFullScale', help='The max and max full scale value for wave.'), # sic, probably "max and min"
_Field('P', 'dataEUnits', default=0, help='Used in memory only. Write zero. Ignore on read.'),
- _Field('P', 'dimEUnits', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS),
- _Field('P', 'dimLabels', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS),
+ _Field('P', 'dimEUnits', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS, array=True),
+ _Field('P', 'dimLabels', default=0, help='Used in memory only. Write zero. Ignore on read.', count=MAXDIMS, array=True),
_Field('P', 'waveNoteH', default=0, help='Used in memory only. Write zero. Ignore on read.'),
- _Field('l', 'whUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=16),
+ _Field('l', 'whUnused', default=0, help='Reserved. Write zero. Ignore on read.', count=16, array=True),
# The following stuff is considered private to Igor.
_Field('h', 'aModified', default=0, help='Used in memory only. Write zero. Ignore on read.'),
_Field('h', 'wModified', default=0, help='Used in memory only. Write zero. Ignore on read.'),
wave_structure = parents[-1]
wave_data = self._get_structure_data(parents, data, wave_structure)
bin_header = wave_data['bin_header']
- d = ''.join(wave_data[self.name])
+ d = wave_data[self.name]
dim_labels = []
start = 0
for size in bin_header[self._size_field]:
end = start + size
if end > start:
dim_data = d[start:end]
- # split null-delimited strings
- labels = dim_data.split(chr(0))
+ chunks = []
+ for i in range(size//32):
+ chunks.append(dim_data[32*i:32*(i+1)])
+ labels = [b'']
+ for chunk in chunks:
+ labels[-1] = labels[-1] + b''.join(chunk)
+ if b'\x00' in chunk:
+ labels.append(b'')
+ labels.pop(-1)
start = end
else:
labels = []
bin_header = wave_data['bin_header']
wave_header = wave_data['wave_header']
self.string_indices_size = bin_header['sIndicesSize']
- self.count = self.string_indices_size / 4
+ self.count = self.string_indices_size // 4
if self.count: # make sure we're in a text wave
assert TYPE_TABLE[wave_header['type']] is None, wave_header
self.setup()
for i,offset in enumerate(wave_data['sIndices']):
if offset > start:
chars = wdata[start:offset]
- strings.append(''.join(chars))
+ strings.append(b''.join(chars))
start = offset
elif offset == start:
- strings.append('')
+ strings.append(b'')
else:
raise ValueError((offset, wave_data['sIndices']))
wdata = _numpy.array(strings)
fields=[
_Field(BinHeader1, 'bin_header', help='Binary wave header'),
_Field(WaveHeader2, 'wave_header', help='Wave header'),
- DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0),
+ DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
])
Wave2 = _DynamicStructure(
fields=[
_Field(BinHeader2, 'bin_header', help='Binary wave header'),
_Field(WaveHeader2, 'wave_header', help='Wave header'),
- DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0),
- _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16),
- DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0),
+ DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
+ _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16, array=True),
+ DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0, array=True),
])
Wave3 = _DynamicStructure(
fields=[
_Field(BinHeader3, 'bin_header', help='Binary wave header'),
_Field(WaveHeader2, 'wave_header', help='Wave header'),
- DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0),
- _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16),
- DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0),
- DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula', count=0),
+ DynamicWaveDataField1('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
+ _Field('x', 'padding', help='16 bytes of padding in versions 2 and 3.', count=16, array=True),
+ DynamicWaveNoteField('c', 'note', help='Optional wave note data', count=0, array=True),
+ DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula', count=0, array=True),
])
Wave5 = _DynamicStructure(
fields=[
_Field(BinHeader5, 'bin_header', help='Binary wave header'),
_Field(WaveHeader5, 'wave_header', help='Wave header'),
- DynamicWaveDataField5('f', 'wData', help='The start of the array of waveform data.', count=0),
- DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula.', count=0),
- DynamicWaveNoteField('c', 'note', help='Optional wave note data.', count=0),
- DynamicDataUnitsField('c', 'data_units', help='Optional extended data units data.', count=0),
- DynamicDimensionUnitsField('c', 'dimension_units', help='Optional dimension label data', count=0),
- DynamicLabelsField('c', 'labels', help="Optional dimension label data", count=0),
- DynamicStringIndicesDataField('P', 'sIndices', help='Dynamic string indices for text waves.', count=0),
+ DynamicWaveDataField5('f', 'wData', help='The start of the array of waveform data.', count=0, array=True),
+ DynamicDependencyFormulaField('c', 'formula', help='Optional wave dependency formula.', count=0, array=True),
+ DynamicWaveNoteField('c', 'note', help='Optional wave note data.', count=0, array=True),
+ DynamicDataUnitsField('c', 'data_units', help='Optional extended data units data.', count=0, array=True),
+ DynamicDimensionUnitsField('c', 'dimension_units', help='Optional dimension label data', count=0, array=True),
+ DynamicLabelsField('c', 'labels', help="Optional dimension label data", count=0, array=True),
+ DynamicStringIndicesDataField('P', 'sIndices', help='Dynamic string indices for text waves.', count=0, array=True),
])
Wave = _DynamicStructure(