dbdreader 0.6.0.dev1__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _dbdreader.cp312-win_amd64.pyd +0 -0
- dbdreader/__init__.py +12 -0
- dbdreader/data/01600000.dcd +0 -0
- dbdreader/data/01600000.ebd +0 -0
- dbdreader/data/01600000.ecd +0 -0
- dbdreader/data/01600000.mcg +0 -0
- dbdreader/data/01600000.mlg +1904 -0
- dbdreader/data/01600001.dbd +0 -0
- dbdreader/data/01600001.dcd +0 -0
- dbdreader/data/01600001.ebd +0 -0
- dbdreader/data/01600001.ecd +0 -0
- dbdreader/data/02380107.ecd +0 -0
- dbdreader/data/02380108.ecd +0 -0
- dbdreader/data/02450133.tcd +0 -0
- dbdreader/data/02450137.tcd +0 -0
- dbdreader/data/amadeus-2014-203-00-000.SBD +0 -0
- dbdreader/data/amadeus-2014-203-00-000.TBD +0 -0
- dbdreader/data/amadeus-2014-204-05-000.dbd +0 -0
- dbdreader/data/amadeus-2014-204-05-000.ebd +0 -0
- dbdreader/data/amadeus-2014-204-05-000.sbd +0 -0
- dbdreader/data/amadeus-2014-204-05-000.tbd +0 -0
- dbdreader/data/amadeus-2014-204-05-001.sbd +0 -0
- dbdreader/data/amadeus-2014-204-05-001.tbd +0 -0
- dbdreader/data/amadeus-2014-204-05-002.sbd +0 -0
- dbdreader/data/amadeus-2014-204-05-002.tbd +0 -0
- dbdreader/data/ammonite-2008-028-01-000.mbd +2091 -1
- dbdreader/data/dbd2asc_output.txt +25 -0
- dbdreader/data/electa-2023-143-00-050.sbd +0 -0
- dbdreader/data/electa-2023-143-00-050.tbd +0 -0
- dbdreader/data/empty-2014-204-05-000.dbd +0 -0
- dbdreader/data/hal_1002-2024-183-4-4.sbd +0 -0
- dbdreader/data/hal_1002-2024-183-4-4.tbd +0 -0
- dbdreader/data/hal_1002-2024-183-4-6.tbd +0 -0
- dbdreader/data/invalid_encoding-2014-204-05-000.dbd +0 -0
- dbdreader/data/sebastian-2014-204-05-000.dbd +0 -0
- dbdreader/data/sebastian-2014-204-05-000.ebd +0 -0
- dbdreader/data/sebastian-2014-204-05-001.dbd +0 -0
- dbdreader/data/sebastian-2014-204-05-001.ebd +0 -0
- dbdreader/data/unit_887-2021-321-3-0.sbd +0 -0
- dbdreader/data/unit_887-2021-321-3-0.tbd +0 -0
- dbdreader/dbdreader.py +2174 -0
- dbdreader/decompress.py +247 -0
- dbdreader/scripts.py +279 -0
- dbdreader-0.6.0.dev1.dist-info/METADATA +272 -0
- dbdreader-0.6.0.dev1.dist-info/RECORD +50 -0
- dbdreader-0.6.0.dev1.dist-info/WHEEL +5 -0
- dbdreader-0.6.0.dev1.dist-info/entry_points.txt +3 -0
- dbdreader-0.6.0.dev1.dist-info/licenses/COPYING +340 -0
- dbdreader-0.6.0.dev1.dist-info/licenses/LICENSE +674 -0
- dbdreader-0.6.0.dev1.dist-info/top_level.txt +2 -0
dbdreader/decompress.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from io import BytesIO as ioBytesIO
|
|
3
|
+
from re import search as re_match
|
|
4
|
+
import lz4.block
|
|
5
|
+
|
|
6
|
+
DECOMPRESSION_ERROR_LIST = ["NO_ERROR",
|
|
7
|
+
"ERROR_UNEXPECTED_END_OF_FILE",
|
|
8
|
+
"ERROR_FILE_NOT_FOUND",
|
|
9
|
+
"ERROR_FAILED_TO_WRITE_BASE_FILE"]
|
|
10
|
+
|
|
11
|
+
class Decompressor:
|
|
12
|
+
'''Class to decompress glider files
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
filename : str
|
|
17
|
+
name of file to decompress
|
|
18
|
+
|
|
19
|
+
This class is designed to be used with a context manager
|
|
20
|
+
|
|
21
|
+
>>> with Decompressor(filename) as d:
|
|
22
|
+
data = d.decompress()
|
|
23
|
+
|
|
24
|
+
Alternatively, a file can be opened a priori
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
>>> d = Decompressor()
|
|
28
|
+
>>> fd = open(filename ,'rb')
|
|
29
|
+
>>> data = d.decompress(fd)
|
|
30
|
+
'''
|
|
31
|
+
SIZEFIELDSIZE = 2
|
|
32
|
+
ENDIANESS = 'big'
|
|
33
|
+
COMPRESSION_FACTOR=10
|
|
34
|
+
CHUNKSIZE = 1024*32
|
|
35
|
+
def __init__(self, filename=None, fp=None):
|
|
36
|
+
self.filename = filename
|
|
37
|
+
self.fp = fp
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def __enter__(self, *p, **kwds):
|
|
41
|
+
# Try to open file is self.filename is given, otherwise check wheter self.fp is given.
|
|
42
|
+
# if not, raise an error.
|
|
43
|
+
if not self.filename is None:
|
|
44
|
+
self.fp = open(self.filename,'rb')
|
|
45
|
+
if self.fp is None:
|
|
46
|
+
raise ValueError('Supply either a filename or file descriptor to the class constructor.')
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
def __exit__(self, *p, **kwds):
|
|
50
|
+
# close the file and leave.
|
|
51
|
+
self.fp.close()
|
|
52
|
+
|
|
53
|
+
def _decompress_block(self, fp=None):
|
|
54
|
+
fp = fp or self.fp
|
|
55
|
+
sb = fp.read(Decompressor.SIZEFIELDSIZE)
|
|
56
|
+
if sb:
|
|
57
|
+
size = int.from_bytes(sb, Decompressor.ENDIANESS)
|
|
58
|
+
b = lz4.block.decompress(fp.read(size), Decompressor.CHUNKSIZE)
|
|
59
|
+
else:
|
|
60
|
+
b = None
|
|
61
|
+
return b
|
|
62
|
+
|
|
63
|
+
def decompressed_blocks(self, n=None, fp=None):
|
|
64
|
+
''' Generator that returns decompressed data blocks
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
n : int or None
|
|
69
|
+
limits the number of blocks read and returned. If None (default) all blocks are returned
|
|
70
|
+
fp : file descriptor or None
|
|
71
|
+
file descriptor to use. If None (default), the file descriptor assigned by the constructor is used.
|
|
72
|
+
|
|
73
|
+
Yields
|
|
74
|
+
------
|
|
75
|
+
bytes:
|
|
76
|
+
decompressed data block
|
|
77
|
+
'''
|
|
78
|
+
counter = 0
|
|
79
|
+
if n is None:
|
|
80
|
+
counter_increment = 0
|
|
81
|
+
n = 1
|
|
82
|
+
else:
|
|
83
|
+
counter_increment = 1
|
|
84
|
+
while counter < n:
|
|
85
|
+
block = self._decompress_block(fp)
|
|
86
|
+
if block is None:
|
|
87
|
+
break
|
|
88
|
+
yield block
|
|
89
|
+
counter+=counter_increment
|
|
90
|
+
|
|
91
|
+
def decompress(self, fp=None):
|
|
92
|
+
''' Decompresses a an entire file (in memory)
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
fp : file descriptor or None
|
|
97
|
+
file descriptor to use. If None (default), the file descriptor assigned by the constructor is used.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
bytes:
|
|
102
|
+
decompressed file data as bytes
|
|
103
|
+
'''
|
|
104
|
+
fp = fp or self.fp
|
|
105
|
+
if fp is None:
|
|
106
|
+
raise ValueError('Supply a file handler or use this class within a context manager')
|
|
107
|
+
data =b''
|
|
108
|
+
for block in self.decompressed_blocks(fp=fp):
|
|
109
|
+
data += block
|
|
110
|
+
return data
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class FileDecompressor:
|
|
114
|
+
'''Class that provides an easy way to automatically decompress a compressed glider
|
|
115
|
+
data file and write it into a normal binary data file.
|
|
116
|
+
|
|
117
|
+
The factual decompressing is done by decompress method.
|
|
118
|
+
|
|
119
|
+
Example
|
|
120
|
+
-------
|
|
121
|
+
|
|
122
|
+
>>> FileDecompressor.decompress("01600000.dcd")
|
|
123
|
+
|
|
124
|
+
which would result in the writing of a decompressed file 01600000.dbd.
|
|
125
|
+
|
|
126
|
+
'''
|
|
127
|
+
def _generate_filename_for_output(self, filename):
|
|
128
|
+
base, ext = os.path.splitext(filename)
|
|
129
|
+
if len(ext)!=4:
|
|
130
|
+
raise ValueError('Unhandled file extension.')
|
|
131
|
+
if ext.endswith('cg'):
|
|
132
|
+
s = 'lg'
|
|
133
|
+
elif ext.endswith('cd'):
|
|
134
|
+
s = 'bd'
|
|
135
|
+
elif ext.endswith('cc'):
|
|
136
|
+
s = 'ac'
|
|
137
|
+
else:
|
|
138
|
+
raise ValueError('Unhandled file extension.')
|
|
139
|
+
return "".join((base, ext[:-2], s))
|
|
140
|
+
|
|
141
|
+
def decompress(self, filename):
|
|
142
|
+
''' Decompresses a file
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
filename : str
|
|
147
|
+
(compressed) filename
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
str:
|
|
152
|
+
uncompressed filename
|
|
153
|
+
|
|
154
|
+
'''
|
|
155
|
+
output_filename = self._generate_filename_for_output(filename)
|
|
156
|
+
with Decompressor(filename) as d, open(output_filename, 'wb') as fp_out:
|
|
157
|
+
for block in d.decompressed_blocks():
|
|
158
|
+
fp_out.write(block)
|
|
159
|
+
return output_filename
|
|
160
|
+
|
|
161
|
+
def decompress_file(filename):
|
|
162
|
+
'''Decompreses a glider data file and writes the normal binary file.'''
|
|
163
|
+
return FileDecompressor().decompress(filename)
|
|
164
|
+
|
|
165
|
+
def is_compressed(filename):
|
|
166
|
+
[basename,ext]=os.path.splitext(filename)
|
|
167
|
+
# all compressed [demnst]bd files end in [demnst]cd
|
|
168
|
+
return bool(re_match("[demnst]c[dg]$", ext))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class BytesIORW:
|
|
172
|
+
''' Helper class implementing a BytesIO buffer that can be written to and read from.
|
|
173
|
+
|
|
174
|
+
Note that the methods write() and readline() are implemented only.
|
|
175
|
+
'''
|
|
176
|
+
def __init__(self, source):
|
|
177
|
+
self.bytesIO = ioBytesIO()
|
|
178
|
+
self.pointer_start = 0
|
|
179
|
+
self.pointer_end = 0
|
|
180
|
+
self.source = source
|
|
181
|
+
|
|
182
|
+
def write(self, b):
|
|
183
|
+
self.pointer_start = self.bytesIO.tell()
|
|
184
|
+
self.bytesIO.write(b)
|
|
185
|
+
self.pointer_end = self.bytesIO.tell()
|
|
186
|
+
self.bytesIO.seek(self.pointer_start)
|
|
187
|
+
self.is_exhausted = False
|
|
188
|
+
|
|
189
|
+
def readline(self):
|
|
190
|
+
line = self.bytesIO.readline()
|
|
191
|
+
pointer = self.bytesIO.tell()
|
|
192
|
+
if pointer == self.pointer_end:
|
|
193
|
+
try:
|
|
194
|
+
self.write(next(self.source))
|
|
195
|
+
except StopIteration:
|
|
196
|
+
pass
|
|
197
|
+
else:
|
|
198
|
+
line+=self.bytesIO.readline()
|
|
199
|
+
return line
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class CompressedFile:
|
|
203
|
+
''' Class to access a compressed file, providing a method
|
|
204
|
+
|
|
205
|
+
readline() that returns a decompressed line of data. The compressed
|
|
206
|
+
file is read block by block, as long as needed.
|
|
207
|
+
|
|
208
|
+
The main reason for the class is to be able to read the header of a compressed
|
|
209
|
+
glider data file.
|
|
210
|
+
'''
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def __init__(self, filename):
|
|
214
|
+
self.filename = filename
|
|
215
|
+
self.decompressor = Decompressor()
|
|
216
|
+
self.bytesIO = None
|
|
217
|
+
|
|
218
|
+
def __enter__(self, *p, **kwds):
|
|
219
|
+
self.fp = open(self.filename, 'rb')
|
|
220
|
+
source = self.decompressor.decompressed_blocks(fp=self.fp)
|
|
221
|
+
self.bytesIO = BytesIORW(source)
|
|
222
|
+
return self
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def __exit__(self, *p, **kwds):
|
|
226
|
+
self.fp.close()
|
|
227
|
+
|
|
228
|
+
def readline(self):
|
|
229
|
+
line = self.bytesIO.readline()
|
|
230
|
+
return line
|
|
231
|
+
|
|
232
|
+
def readlines(self):
|
|
233
|
+
while True:
|
|
234
|
+
line = self.readline()
|
|
235
|
+
if not line:
|
|
236
|
+
break
|
|
237
|
+
yield line
|
|
238
|
+
|
|
239
|
+
def seek(self, offset):
|
|
240
|
+
return self.bytesIO.bytesIO.seek(offset)
|
|
241
|
+
|
|
242
|
+
def tell(self):
|
|
243
|
+
return self.bytesIO.bytesIO.tell()
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def close(self):
|
|
247
|
+
self.fp.close()
|
dbdreader/scripts.py
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Copyright 2006,2007,2014, 2023 Lucas Merckelbach
|
|
2
|
+
#
|
|
3
|
+
# This file is part of dbdreader.
|
|
4
|
+
#
|
|
5
|
+
# dbdreader is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# dbdreader is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
6#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with dbdreader. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
from collections import OrderedDict
|
|
20
|
+
import sys
|
|
21
|
+
import os
|
|
22
|
+
import argparse
|
|
23
|
+
import re
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
import dbdreader.decompress
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _makeSortable(filename):
|
|
31
|
+
[basename,ext]=filename.split('.')
|
|
32
|
+
[g,y,d,m,s]=basename.split('-')
|
|
33
|
+
s="%03d"%(int(s))
|
|
34
|
+
m="%02d"%(int(m))
|
|
35
|
+
d="%03d"%(int(d))
|
|
36
|
+
basename="-".join([g,y,d,m,s])
|
|
37
|
+
filename=".".join([basename,ext])
|
|
38
|
+
return(filename)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_short_and_long_filenames(lines, filename):
|
|
44
|
+
ID=lines[0]
|
|
45
|
+
ignoreIt=False
|
|
46
|
+
shortfilename=''
|
|
47
|
+
longfilename=''
|
|
48
|
+
if ID=='dbd_label: DBD(dinkum_binary_data)file':
|
|
49
|
+
shortfilename=lines[4]
|
|
50
|
+
longfilename=lines[5]
|
|
51
|
+
shortfilename=re.sub(r"^.* ","",shortfilename)
|
|
52
|
+
longfilename=re.sub(r"^.* ","",longfilename)
|
|
53
|
+
extension=re.sub(r"^.*\.","",filename)
|
|
54
|
+
shortfilename+="."+extension
|
|
55
|
+
longfilename+="."+extension
|
|
56
|
+
elif "the8x3_filename" in ID: # mlg file apparently...
|
|
57
|
+
longfilename=lines[1]
|
|
58
|
+
if filename.lower().endswith('mlg'):
|
|
59
|
+
extension='.mlg'
|
|
60
|
+
else:
|
|
61
|
+
extension='.nlg'
|
|
62
|
+
shortfilename=re.sub(r"^the8x3_filename: +","",ID+extension)
|
|
63
|
+
|
|
64
|
+
longfilename=re.sub(r"^full_filename: +","",longfilename)+extension
|
|
65
|
+
else:
|
|
66
|
+
sys.stderr.write("Ignoring %s\n"%(filename))
|
|
67
|
+
ignoreIt=True
|
|
68
|
+
return ignoreIt, shortfilename, longfilename
|
|
69
|
+
|
|
70
|
+
def dbdrename():
|
|
71
|
+
''' Standalone script to rename dbd files
|
|
72
|
+
|
|
73
|
+
Use dbdrename -h for help.
|
|
74
|
+
'''
|
|
75
|
+
parser = argparse.ArgumentParser(
|
|
76
|
+
prog='dbdrename',
|
|
77
|
+
description='''Program to rename dbd files and friends from numeric format to long format, or vice versa,
|
|
78
|
+
or convert the long format into a sortable name or the original Webb Research long format,
|
|
79
|
+
or decompress LZ4 compressed files.''',
|
|
80
|
+
epilog='')
|
|
81
|
+
|
|
82
|
+
parser.add_argument('filenames', nargs="*", help="Filename(s) to process")
|
|
83
|
+
parser.add_argument('-s', action='store_true', default=True, help='Ensures long format filenames are sortable')
|
|
84
|
+
parser.add_argument('-n', action='store_true', help='Keeps the original long format filenames (which do not sort correctly).')
|
|
85
|
+
parser.add_argument('-c', '--convertToSortable', action='store_true', help='Converts files from original long format to a sortable long format')
|
|
86
|
+
parser.add_argument('-C', '--convertToOriginal', action='store_true', help='Converts files from a sortable long format to the original long format')
|
|
87
|
+
parser.add_argument('-x', '--decompress', action='store_true', help='Decompresses LZ4 comrpessed files.')
|
|
88
|
+
parser.add_argument('-X', '--decompressAndRemoveCompressed', action='store_true', help='Decompresses LZ4 comrpessed files, and removes the compressed file')
|
|
89
|
+
parser.add_argument('-d', '--doNotChangeNameFormat', action='store_true', help='Does not change the filename format. (Only useful in combination with -x or -X)')
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
args = parser.parse_args()
|
|
94
|
+
|
|
95
|
+
# override the default value of -s if -d is specified
|
|
96
|
+
if args.doNotChangeNameFormat:
|
|
97
|
+
args.s=False
|
|
98
|
+
|
|
99
|
+
for i in args.filenames:
|
|
100
|
+
if not os.path.exists(i):
|
|
101
|
+
print(f"{i} does not exist. Ignoring.")
|
|
102
|
+
continue
|
|
103
|
+
if dbdreader.decompress.is_compressed(i):
|
|
104
|
+
with dbdreader.decompress.CompressedFile(i) as fd:
|
|
105
|
+
lines = [fd.readline().decode('ascii').strip() for j in range(7)]
|
|
106
|
+
else:
|
|
107
|
+
with open(i,'br') as fd:
|
|
108
|
+
lines = [fd.readline().decode('ascii').strip() for j in range(7)]
|
|
109
|
+
ignoreIt, shortfilename, longfilename = _get_short_and_long_filenames(lines, i)
|
|
110
|
+
|
|
111
|
+
basename = os.path.basename(i)
|
|
112
|
+
prefix = i.replace(basename, "")
|
|
113
|
+
|
|
114
|
+
if not ignoreIt:
|
|
115
|
+
command=None
|
|
116
|
+
if args.convertToSortable or args.convertToOriginal: # input filename must be the longfilename
|
|
117
|
+
# check if we have a longfilename
|
|
118
|
+
if i not in [longfilename,_makeSortable(longfilename)]:
|
|
119
|
+
print("Chose to ignore processing ",i)
|
|
120
|
+
else:
|
|
121
|
+
if i==_makeSortable(longfilename) and args.convertToOriginal:
|
|
122
|
+
# switch to old format
|
|
123
|
+
command="mv "+i+" "+longfilename
|
|
124
|
+
new_filename = longfilename
|
|
125
|
+
elif i==longfilename and args.convertToSortable:
|
|
126
|
+
command="mv "+longfilename+" "+_makeSortable(longfilename)
|
|
127
|
+
new_filename = _makeSortable(longfilename)
|
|
128
|
+
else:
|
|
129
|
+
print("ignoring "+i)
|
|
130
|
+
else: # changing from long to short names or vice versa
|
|
131
|
+
if not args.n and not args.s: # -d has been requested
|
|
132
|
+
new_filename = i
|
|
133
|
+
if args.decompress or args.decompressAndRemoveCompressed:
|
|
134
|
+
command = ""
|
|
135
|
+
else: # create the new_filename by translating
|
|
136
|
+
if args.s and not args.n:
|
|
137
|
+
longfilename=_makeSortable(longfilename)
|
|
138
|
+
if basename==shortfilename:
|
|
139
|
+
new_filename = os.path.join(prefix, longfilename)
|
|
140
|
+
old_filename = os.path.join(prefix, shortfilename)
|
|
141
|
+
command = f"mv {old_filename} {new_filename}"
|
|
142
|
+
else:
|
|
143
|
+
new_filename = os.path.join(prefix, shortfilename)
|
|
144
|
+
old_filename = os.path.join(prefix, longfilename)
|
|
145
|
+
command = f"mv {old_filename} {new_filename}"
|
|
146
|
+
|
|
147
|
+
if command!=None:
|
|
148
|
+
target = new_filename
|
|
149
|
+
if command:
|
|
150
|
+
R=os.system(command)
|
|
151
|
+
else:
|
|
152
|
+
R=0
|
|
153
|
+
msg = f"{i} ->"
|
|
154
|
+
if R!=0:
|
|
155
|
+
raise ValueError("Could not execute %s"%(command))
|
|
156
|
+
if args.decompress or args.decompressAndRemoveCompressed:
|
|
157
|
+
try:
|
|
158
|
+
target = dbdreader.decompress.decompress_file(new_filename)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
msg = e
|
|
161
|
+
else:
|
|
162
|
+
if args.decompressAndRemoveCompressed:
|
|
163
|
+
os.unlink(new_filename)
|
|
164
|
+
msg = f"{msg} {target}"
|
|
165
|
+
else:
|
|
166
|
+
msg = f"{msg} {target}/{new_filename}"
|
|
167
|
+
else:
|
|
168
|
+
msg = f"{msg} {target}"
|
|
169
|
+
print(msg)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
''' =====================================================================================================
|
|
173
|
+
|
|
174
|
+
cac_gen
|
|
175
|
+
|
|
176
|
+
===================================================================================================== '''
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _parse_line(line):
|
|
180
|
+
fields=line.rstrip().split()
|
|
181
|
+
s=dict(flag=fields[1],
|
|
182
|
+
global_index=int(fields[2]),
|
|
183
|
+
index=int(fields[3]),
|
|
184
|
+
bytesize=int(fields[4]),
|
|
185
|
+
name=fields[5],
|
|
186
|
+
unit=fields[6])
|
|
187
|
+
return s['name'],s
|
|
188
|
+
|
|
189
|
+
def _read_cac_file(fn):
|
|
190
|
+
sensors=OrderedDict()
|
|
191
|
+
fd=open(fn,'r')
|
|
192
|
+
while True:
|
|
193
|
+
line=fd.readline()
|
|
194
|
+
if not line:
|
|
195
|
+
break
|
|
196
|
+
n,s=_parse_line(line)
|
|
197
|
+
sensors[n]=s
|
|
198
|
+
fd.close()
|
|
199
|
+
return sensors
|
|
200
|
+
|
|
201
|
+
def _read_mbdlist(fn):
|
|
202
|
+
params=[]
|
|
203
|
+
fd=open(fn,'r')
|
|
204
|
+
while True:
|
|
205
|
+
line=fd.readline()
|
|
206
|
+
if not line:
|
|
207
|
+
break
|
|
208
|
+
line=line.rstrip().lstrip()
|
|
209
|
+
if not line:
|
|
210
|
+
continue # empty line
|
|
211
|
+
if line.startswith("#"):
|
|
212
|
+
continue
|
|
213
|
+
s=line.lower().split()
|
|
214
|
+
params.append(s[0])
|
|
215
|
+
fd.close()
|
|
216
|
+
return params
|
|
217
|
+
|
|
218
|
+
def _generate_cac(s,params):
|
|
219
|
+
# sort params:
|
|
220
|
+
params_in_order=[]
|
|
221
|
+
for k in list(s.keys()):
|
|
222
|
+
if k in params:
|
|
223
|
+
params_in_order.append(k)
|
|
224
|
+
# set all indices to -1
|
|
225
|
+
for v in s.values():
|
|
226
|
+
v['index']=-1
|
|
227
|
+
v['flag']='F'
|
|
228
|
+
for i,p in enumerate(params_in_order):
|
|
229
|
+
s[p]['index']=i
|
|
230
|
+
s[p]['flag']='T'
|
|
231
|
+
return s
|
|
232
|
+
|
|
233
|
+
def _write_cac(s,fd):
|
|
234
|
+
for k,v in s.items():
|
|
235
|
+
fd.write("s: %s%5d%5d%2d %s %s\n"%(v['flag'],
|
|
236
|
+
v['global_index'],
|
|
237
|
+
v['index'],
|
|
238
|
+
v['bytesize'],
|
|
239
|
+
v['name'],
|
|
240
|
+
v['unit']))
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _generate_cac_file(mbdlist_filename,template,output):
|
|
244
|
+
s=_read_cac_file(template)
|
|
245
|
+
params=_read_mbdlist(mbdlist_filename)
|
|
246
|
+
s=_generate_cac(s,params)
|
|
247
|
+
if output:
|
|
248
|
+
fd=open(output,'w')
|
|
249
|
+
_write_cac(s,fd)
|
|
250
|
+
fd.close()
|
|
251
|
+
else:
|
|
252
|
+
_write_cac(s,sys.stdout)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def cac_gen():
|
|
256
|
+
''' A script to generate cac files
|
|
257
|
+
|
|
258
|
+
run cac_gen -h for more help.
|
|
259
|
+
'''
|
|
260
|
+
parser = argparse.ArgumentParser(
|
|
261
|
+
prog='cac_gen',
|
|
262
|
+
description='''A program to generate a valid cache file from a .dat file and a valid cache file for this
|
|
263
|
+
glider.
|
|
264
|
+
|
|
265
|
+
For example, if you have a cache file for an sbd file, and the sbdlist.dat got modified, then this programs
|
|
266
|
+
let's you build a new cache file using the old cache file and new sdblist.dat file as input.
|
|
267
|
+
''',
|
|
268
|
+
epilog='')
|
|
269
|
+
|
|
270
|
+
parser.add_argument('sdblist', help="sdblist.dat file, specifying which parameters are present in the binary files")
|
|
271
|
+
parser.add_argument('cachefile', help="A valid and exisiting cache file for this glider.")
|
|
272
|
+
parser.add_argument('outputfile', nargs="?", default=None, help="Output filename (writes to stdout if not speficied.)")
|
|
273
|
+
|
|
274
|
+
args = parser.parse_args()
|
|
275
|
+
_generate_cac_file(args.sdblist, args.cachefile, args.outputfile)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|