/
FixedRecordFile.py
executable file
·200 lines (178 loc) · 6.22 KB
/
FixedRecordFile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import os
import io
import sys
import traceback
import math
import logging
from . import ti_files
from Pab import *
logger = logging.getLogger(__name__)
class FixedRecordFile(object):
def __init__(self, bytes, pab):
self.dirty = False
self.header = bytes[:128]
self.mode = mode(pab)
self.filetype = fileType(pab)
self.recordLength = ti_files.recordLength(self.header)
if self.mode == OUTPUT and self.filetype == SEQUENTIAL:
self.records = []
self.dirty = True
else:
self.records = self.__loadRecords(bytes[128:])
if self.mode == APPEND:
self.currentRecord = len(self.records)
else:
self.currentRecord = 0
logger.info(
"records loaded: %d, currentRecord: %d, recordLength: %d",
len(self.records),
self.currentRecord,
self.recordLength,
)
@staticmethod
def create(devname, localpath, pab):
nameParts = str(devname).split(".")
tiname = nameParts[len(nameParts) - 1]
recLen = recordLength(pab)
if recLen == 0:
recLen = 80
# FIXED is default (or flag clear/unset)
flags = 0
if dataType(pab) == INTERNAL:
flags |= ti_files.INTERNAL
header = ti_files.createHeader(flags, tiname, bytearray(0))
ti_files.setRecordLength(header, recLen)
ti_files.setRecordsPerSector(header, int(256 / recLen))
recordFile = FixedRecordFile(header, pab)
recordFile.dirty = True
return recordFile
@staticmethod
def load(unix_file_name, pab):
fh = None
try:
fh = open(unix_file_name, "rb")
fdata = bytearray(fh.read())
# Check that request matches DISPLAY or INTERNAL of file
ti_files.validateDataType(fdata, dataType(pab))
# Check that target file is valid
if not ti_files.isValid(fdata):
raise Exception("invaid TIFILE")
# Check that we are a FIXED record file
if ti_files.isVariable(fdata):
raise Exception("file is variable")
return FixedRecordFile(fdata, pab)
except Exception as e:
logger.error("File does not match PAB type: %s", unix_file_name)
return None
finally:
if fh != None:
fh.close()
def isLegal(self, pab):
return recordType(pab) == FIXED
def getStatusByte(self):
statByte = 0
if ti_files.isInternal(self.header):
statByte |= STINTERNAL
if self.currentRecord >= len(self.records):
statByte |= STLEOF
return statByte
def restore(self, pab):
logger.info("restore for file type: %d", self.filetype)
if self.filetype == RELATIVE:
self.currentRecord = recordNumber(pab)
else:
self.currentRecord = 0
def writeRecord(self, rdata, pab):
self.dirty = True
recNo = recordNumber(pab)
if self.filetype == RELATIVE:
self.currentRecord = recNo
logger.info(f'currentRecord: {self.currentRecord}')
if self.currentRecord >= len(self.records):
logger.info("growing records")
self.records += [bytearray(self.recordLength)] * (
1 + self.currentRecord - len(self.records)
)
new_record = bytearray(self.recordLength)
new_record[: len(rdata)] = bytearray(rdata)
self.records[self.currentRecord] = new_record
logger.info(
"set record %d to bytes of length %d", self.currentRecord, len(rdata)
)
self.currentRecord += 1
def readRecord(self, idx):
if self.filetype == RELATIVE:
self.currentRecord = idx
logger.info("reading currentRecord: %d", self.currentRecord)
record = self.getRecord(self.currentRecord)
self.currentRecord += 1
return record
def getRecord(self, idx):
if idx >= len(self.records):
return None
return self.records[idx]
def getRecordLength(self):
return self.recordLength
def __loadRecords(self, bytes):
count = ti_files.recordCount(self.header)
idx = 0
records = []
while idx < count:
record = self.__recordBytes(bytes, idx)
if record == None:
break
records.append(record)
idx += 1
return records
def __recordBytes(self, bytes, idx):
recPerSec = int(256 / self.recordLength)
secNumber = int(idx / recPerSec)
recInSec = idx % recPerSec
start = (secNumber * 256) + (recInSec * self.recordLength)
end = start + self.recordLength
return bytes[start:end]
def close(self, localPath):
if self.dirty:
try:
bytes = self.__packRecords()
fh = open(localPath, "wb")
fh.write(bytes)
fh.close()
self.dirty = False
except Exception as e:
logger.exception("Failed to save fixed file %s", localPath)
def eager_write(self, localPath):
self.close(localPath)
def __packRecords(self):
recLen = self.recordLength
sectors = []
sector = bytearray(256)
recNo = 0
offset = 0
while recNo < len(self.records):
rec = self.records[recNo]
if (256 - offset) < (recLen):
sectors += [sector]
offset = 0
sector = bytearray(256)
sector[offset : offset + recLen] = rec
offset += recLen
recNo += 1
if offset != 0:
sectors += [sector]
sectorCount = len(sectors)
header = bytearray(self.header)
ti_files.setSectors(header, sectorCount)
if offset == 256:
offset = 0
ti_files.setEofOffset(header, offset)
ti_files.setRecordCount(header, len(self.records))
bytes = bytearray(128 + (sectorCount * 256))
bytes[:128] = header
idx = 128
sec = 0
while sec < sectorCount:
bytes[idx:] = sectors[sec]
sec += 1
idx += 256
return bytes