Split record handling into modules and implement VariablesRecord.
[igor.git] / igor / packed.py
1 # Copyright
2
3 "Read IGOR Packed Experiment files files into records."
4
5 from .struct import Structure as _Structure
6 from .struct import Field as _Field
7 from .util import byte_order as _byte_order
8 from .util import need_to_reorder_bytes as _need_to_reorder_bytes
9 from .record import RECORD_TYPE as _RECORD_TYPE
10 from .record.base import UnknownRecord as _UnknownRecord
11 from .record.base import UnusedRecord as _UnusedRecord
12
13
14 # Igor writes other kinds of records in a packed experiment file, for
15 # storing things like pictures, page setup records, and miscellaneous
16 # settings.  The format for these records is quite complex and is not
17 # described in PTN003.  If you are writing a program to read packed
18 # files, you must skip any record with a record type that is not
19 # listed above.
20
21 PackedFileRecordHeader = _Structure(
22     name='PackedFileRecordHeader',
23     fields=[
24         _Field('H', 'recordType', help='Record type plus superceded flag.'),
25         _Field('h', 'version', help='Version information depends on the type of record.'),
26         _Field('l', 'numDataBytes', help='Number of data bytes in the record following this record header.'),
27         ])
28
29 #CR_STR = '\x15'  (\r)
30
31 PACKEDRECTYPE_MASK = 0x7FFF  # Record type = (recordType & PACKEDREC_TYPE_MASK)
32 SUPERCEDED_MASK = 0x8000  # Bit is set if the record is superceded by
33                           # a later record in the packed file.
34
35
36 def load(filename, strict=True, ignore_unknown=True):
37     records = []
38     if hasattr(filename, 'read'):
39         f = filename  # filename is actually a stream object
40     else:
41         f = open(filename, 'rb')
42     byte_order = None
43     initial_byte_order = '='
44     try:
45         while True:
46             b = buffer(f.read(PackedFileRecordHeader.size))
47             if not b:
48                 break
49             PackedFileRecordHeader.set_byte_order(initial_byte_order)
50             header = PackedFileRecordHeader.unpack_from(b)
51             if header['version'] and not byte_order:
52                 need_to_reorder = _need_to_reorder_bytes(header['version'])
53                 byte_order = initial_byte_order = _byte_order(need_to_reorder)
54                 if need_to_reorder:
55                     PackedFileRecordHeader.set_byte_order(byte_order)
56                     header = PackedFileRecordHeader.unpack_from(b)
57             data = buffer(f.read(header['numDataBytes']))
58             record_type = _RECORD_TYPE.get(
59                 header['recordType'] & PACKEDRECTYPE_MASK, _UnknownRecord)
60             if record_type in [_UnknownRecord, _UnusedRecord
61                                ] and not ignore_unknown:
62                 raise KeyError('unkown record type {}'.format(
63                         header['recordType']))
64             records.append(record_type(header, data, byte_order=byte_order))
65     finally:
66         if not hasattr(filename, 'read'):
67             f.close()
68
69     return records
70