123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import struct
- from greaseweazle import error
- from greaseweazle.track import MasterTrack, RawTrack
- from bitarray import bitarray
- from .image import Image
- class HFE(Image):
- def __init__(self):
- self.bitrate = 250
-
-
- self.to_track = dict()
- @classmethod
- def from_file(cls, name):
- with open(name, "rb") as f:
- dat = f.read()
- (sig, f_rev, n_cyl, n_side, t_enc, bitrate,
- _, _, _, tlut_base) = struct.unpack("<8s4B2H2BH", dat[:20])
- error.check(sig != b"HXCHFEV3", "HFEv3 is not supported")
- error.check(sig == b"HXCPICFE" and f_rev <= 1, "Not a valid HFE file")
- error.check(0 < n_cyl, "HFE: Invalid #cyls")
- error.check(0 < n_side < 3, "HFE: Invalid #sides")
- error.check(bitrate != 0, "HFE: Invalid bitrate")
- hfe = cls()
- hfe.bitrate = bitrate
- tlut = dat[tlut_base*512:tlut_base*512+n_cyl*4]
-
- for cyl in range(n_cyl):
- for side in range(n_side):
- offset, length = struct.unpack("<2H", tlut[cyl*4:(cyl+1)*4])
- todo = length // 2
- tdat = bytes()
- while todo:
- d_off = offset*512 + side*256
- d_nr = 256 if todo > 256 else todo
- tdat += dat[d_off:d_off+d_nr]
- todo -= d_nr
- offset += 1
- hfe.to_track[cyl,side] = (len(tdat)*8, tdat)
- return hfe
- def get_track(self, cyl, side):
- if (cyl,side) not in self.to_track:
- return None
- bitlen, rawbytes = self.to_track[cyl,side]
- tdat = bitarray(endian='little')
- tdat.frombytes(rawbytes)
- track = MasterTrack(
- bits = tdat[:bitlen],
- time_per_rev = bitlen / (2000*self.bitrate))
- return track
- def emit_track(self, cyl, side, track):
- flux = track.flux()
- flux.cue_at_index()
- raw = RawTrack(clock = 5e-4 / self.bitrate, data = flux)
- bits, _ = raw.get_revolution(0)
- bits.bytereverse()
- self.to_track[cyl,side] = (len(bits), bits.tobytes())
- def get_image(self):
- n_side = 1
- n_cyl = max(self.to_track.keys(), default=(0), key=lambda x:x[0])[0]
- n_cyl += 1
-
- tlut = bytearray()
- tdat = bytearray()
-
- for i in range(n_cyl):
- s0 = self.to_track[i,0] if (i,0) in self.to_track else None
- s1 = self.to_track[i,1] if (i,1) in self.to_track else None
- if s0 is None and s1 is None:
-
- nr_bytes = 100 * self.bitrate
- tlut += struct.pack("<2H", len(tdat)//512 + 2, nr_bytes)
- tdat += bytes([0x88] * (nr_bytes+0x1ff & ~0x1ff))
- else:
-
- if s1 is not None:
- n_side = 2
- bc = [s0 if s0 is not None else (0,bytes()),
- s1 if s1 is not None else (0,bytes())]
- nr_bytes = max(len(t[1]) for t in bc)
- nr_blocks = (nr_bytes + 0xff) // 0x100
- tlut += struct.pack("<2H", len(tdat)//512 + 2, 2 * nr_bytes)
- for b in range(nr_blocks):
- for t in bc:
- slice = t[1][b*256:(b+1)*256]
- tdat += slice + bytes([0x88] * (256 - len(slice)))
-
- header = struct.pack("<8s4B2H2BH",
- b"HXCPICFE",
- 0,
- n_cyl,
- n_side,
- 0xff,
- self.bitrate,
- 0,
- 0xff,
- 1,
- 1)
-
- header += bytes([0xff] * (0x200 - len(header)))
- tlut += bytes([0xff] * (0x200 - len(tlut)))
- return header + tlut + tdat
|