-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathls_OPK.py
180 lines (152 loc) · 5.61 KB
/
ls_OPK.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
# -*- coding: utf-8 -*-
"""
OPK file reader
Created: Sept 2022
@author: martin
"""
# import os
# file1 = "comms42.opk"
# file1 = "rampak_colours.opk"
file1 = "testpak.opk"
# file1 = "test.opk"
dat = [] # file data
# read file data
print(f'File {file1:s}:')
# fs = os.path.getsize(f)
# print(f'File size is: {fs:d} bytes')
with open(file1,'rb') as fid:
fid.seek(0,2) # go to the file end, 2-rel. to end
fs = fid.tell() # get the end of file location
fid.seek(0,0) # go back to file beginning, 0-abs
print(f'File size: {fs:d}')
eof = False
addr = 0
# fs = 5
while not eof:
b = ord(fid.read(1))
# print(addr, b)
dat.append(b)
addr += 1
if addr == fs:
eof = True
ds = len(dat)
print(f'bytes read: {ds:d} 0x{ds:06x}')
# print OPK header and remove it
header = []
for i in range(6):
header.append(dat[i])
print('OPK Header:',header)
size_hh = header[3]
size_h = header[4]
size_l = header[5]
size = (size_hh << 16) + (size_h << 8) + size_l # shift size_hh left 16 bits, size_h left 8 bits
print(f'size_hh: 0x{size_hh:02x} size_h: 0x{size_h:02x}, size_l: 0x{size_l:02x}, size: 0x{size:06x} {size:d}')
dat = dat[6::] # cut out OPK header bytes
# size & list pack
start = 0x0A # records start after ID bytes at address 10
# i = np.uint32(start) # address i is 32 bit integer
i = start
print('Record list:')
bsr = 0 # bad short record count
sr = 0 # short record count
lr = 0 # long record count
end_of_pack = False
r_types = {0x80:'long',0x81:'data',0x82:'diary',0x83:'OPL',0x84:'comms',0x85:'sheet',0x86:'pager',0x87:'notes'}
df_id = [] # list to store data file IDs
df_name = [] # list to store data file names
while not end_of_pack:
if i >= 0x10000: # limit read size here, if needed
end_of_pack = True
rec_len = dat[i] # 1st byte is record length
if rec_len == 0xFF: # end of pack
skp = 0
end_of_pack = True
print(f'0x{i:04x} end of pack')
break
rec_type = dat[i+1] # 2nd byte is record type (only 2 main types: short or long)
r_type = rec_type | 0x80 # OR with 0x80, as could be deleted
if rec_type == 0xFF: # bad short record
skp = 2 # ignore length if bad, skip past length and type bytes
bsr += 1
print(f'0x{i:04x} bad short record')
elif rec_type == 0x80: # long record - preceding short record has: deleted?, type, filename
skp = (dat[i+2] << 8) + dat[i+3] + 4 # high byte, low byte of long rec length
lr += 1
print(f'0x{i:04x} Long Length: 0x{skp-4:04x} skip :0x{skp:04x}')
else: # short record
skp = rec_len + 2
sr += 1
r_string = ''
for sl in range(rec_len): # build record string
c = dat[i+2+sl]
r_string += chr(c)
if rec_type >> 7: # shift right 7 bits to see if MSB is high - not deleted
r_del = 'n' # not deleted
else:
r_del = 'y' # deleted
if r_type == 0x81: # datafile so read name and file ID (0x90 for main)
r_string = r_string[0:8] # file names are always 8 chars (range end value is exclusive)
df_id.append(dat[i+10]) # store datafile ID
df_name.append(r_string.strip()) # store datafile name & strip spaces
r_type_s = f'datafile ID: {dat[i+10]:02x}'
elif r_type >= 0x82 and r_type <= 0x8F:
try:
r_type_s = r_types[r_type] # try looking up record type in dictionary
except:
r_type_s = 'unknown' # if not in dictionary - unknown
elif r_type >= 0x90 and r_type <= 0xFE: # record from datafile with ID
try:
p = df_id.index(r_type) # look for datafile ID in list
dfn = df_name[p] # get name from list
except:
dfn = 'ID not found'
r_type_s = f'record from datafile ID: {r_type:02x} {dfn:s}'
else:
r_type_s = 'unknown' # not any of the above
print(f'0x{i:04x} Short Length: 0x{skp-2:04x} skip: 0x{skp:04x} deleted?: {r_del:s} Type: 0x{dat[i+1]:02x} {r_type_s:s} : {r_string:s}')
i = i + skp
print(f'bad short records: {bsr:d}')
print(f'short records: {sr:d}')
print(f'long records: {lr:d}')
print(f'pack size: 0x{i:04x} {i:d}')
if i == size:
print('Sizing matches OPK size!')
else:
print('Sizing does not match OPK size!!')
# display pack data
data = dat
check_blank = False
print("\naddr 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F TEXT")
print("---------------------------------------------------------------")
# size = 0x200
l = (size-1) // 16 # div (no. of complete 16's in size)
n = 15 - (size % 16) # fill in rest of 16 with zero's - just for printing
for i in range(n):
data.append(0)
start = 0x00
end_addr = start + size
addr = start
ext = False
for j in range(l+1): # no. of sets 16 bytes
out = ""
dat2 = []
if addr > size:
break
for k in range(16):
c = data[addr]
if check_blank == True and c != 0xFF:
print(f'Non 0xFF byte: {c:02x} found at {addr:04x}')
ext = True
dat2.append(c)
addr += 1
if 127 < c or c < 32:
c = 46 # .
out = out + chr(c)
if k == 7:
out = out +" "
if addr >= end_addr:
ext = True
base = j*16
print(f"{start+base:04x} {dat2[0]:02x} {dat2[1]:02x} {dat2[2]:02x} {dat2[3]:02x} {dat2[4]:02x} {dat2[5]:02x} {dat2[6]:02x} {dat2[7]:02x} {dat2[8]:02x} {dat2[9]:02x} {dat2[10]:02x} {dat2[11]:02x} {dat2[12]:02x} {dat2[13]:02x} {dat2[14]:02x} {dat2[15]:02x} {out:s}")
if ext == True:
break