-# Copyright
+# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
+#
+# This file is part of igor.
+#
+# 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.
+#
+# 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 igor. If not, see <http://www.gnu.org/licenses/>.
"Read IGOR Packed Experiment files files into records."
+from . import LOG as _LOG
from .struct import Structure as _Structure
from .struct import Field as _Field
from .util import byte_order as _byte_order
def load(filename, strict=True, ignore_unknown=True):
+ _LOG.debug('loading a packed experiment file from {}'.format(filename))
records = []
if hasattr(filename, 'read'):
f = filename # filename is actually a stream object
initial_byte_order = '='
try:
while True:
+ PackedFileRecordHeader.byte_order = initial_byte_order
+ PackedFileRecordHeader.setup()
b = buffer(f.read(PackedFileRecordHeader.size))
if not b:
break
- PackedFileRecordHeader.set_byte_order(initial_byte_order)
+ if len(b) < PackedFileRecordHeader.size:
+ raise ValueError(
+ ('not enough data for the next record header ({} < {})'
+ ).format(len(b), PackedFileRecordHeader.size))
+ _LOG.debug('reading a new packed experiment file record')
header = PackedFileRecordHeader.unpack_from(b)
if header['version'] and not byte_order:
need_to_reorder = _need_to_reorder_bytes(header['version'])
byte_order = initial_byte_order = _byte_order(need_to_reorder)
+ _LOG.debug(
+ 'get byte order from version: {} (reorder? {})'.format(
+ byte_order, need_to_reorder))
if need_to_reorder:
- PackedFileRecordHeader.set_byte_order(byte_order)
+ PackedFileRecordHeader.byte_order = byte_order
+ PackedFileRecordHeader.setup()
header = PackedFileRecordHeader.unpack_from(b)
+ _LOG.debug(
+ 'reordered version: {}'.format(header['version']))
data = buffer(f.read(header['numDataBytes']))
+ if len(data) < header['numDataBytes']:
+ raise ValueError(
+ ('not enough data for the next record ({} < {})'
+ ).format(len(b), header['numDataBytes']))
record_type = _RECORD_TYPE.get(
header['recordType'] & PACKEDRECTYPE_MASK, _UnknownRecord)
+ _LOG.debug('the new record has type {} ({}).'.format(
+ record_type, header['recordType']))
if record_type in [_UnknownRecord, _UnusedRecord
] and not ignore_unknown:
raise KeyError('unkown record type {}'.format(
header['recordType']))
records.append(record_type(header, data, byte_order=byte_order))
finally:
+ _LOG.debug('finished loading {} records from {}'.format(
+ len(records), filename))
if not hasattr(filename, 'read'):
f.close()
+ filesystem = _build_filesystem(records)
+
+ return (records, filesystem)
+
+def _build_filesystem(records):
# From PTN003:
"""The name must be a valid Igor data folder name. See Object
Names in the Igor Reference help file for name rules.
dir_stack.pop()
elif isinstance(record, (_VariablesRecord, _WaveRecord)):
if isinstance(record, _VariablesRecord):
- filename = ':variables' # start with an invalid character
- else: # to avoid collisions with folder
- filename = ':waves' # names
- if filename in cwd:
- cwd[filename].append(record)
- else:
- cwd[filename] = [record]
-
- return (records, filesystem)
+ sys_vars = record.variables['variables']['sysVars'].keys()
+ for filename,value in record.namespace.items():
+ if len(dir_stack) > 1 and filename in sys_vars:
+ # From PTN003:
+ """When reading a packed file, any system
+ variables encountered while the current data
+ folder is not the root should be ignored.
+ """
+ continue
+ _check_filename(dir_stack, filename)
+ cwd[filename] = value
+ else: # WaveRecord
+ filename = record.wave['wave']['wave_header']['bname']
+ _check_filename(dir_stack, filename)
+ cwd[filename] = record
+ return filesystem
+def _check_filename(dir_stack, filename):
+ cwd = dir_stack[-1][-1]
+ if filename in cwd:
+ raise ValueError('collision on name {} in {}'.format(
+ filename, ':'.join(d for d,cwd in dir_stack)))