| 
					
				 | 
			
			
				@@ -14,13 +14,11 @@ from .image import Image 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class HFE(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def __init__(self, start_cyl, nr_sides): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.start_cyl = start_cyl 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.nr_sides = nr_sides 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.bitrate = 250 # XXX real bitrate? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Each track is (bitlen, rawbytes). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # rawbytes is a bytes() object in little-endian bit order. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.track_list = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.to_track = dict() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @classmethod 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -29,21 +27,21 @@ class HFE(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         with open(name, "rb") as f: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             dat = f.read() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        (sig, f_rev, nr_cyls, nr_sides, t_enc, bitrate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (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 < nr_cyls, "HFE: Invalid #cyls") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        error.check(0 < nr_sides < 3, "HFE: Invalid #sides") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        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(0, nr_sides) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        hfe = cls() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         hfe.bitrate = bitrate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        tlut = dat[tlut_base*512:tlut_base*512+nr_cyls*4] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tlut = dat[tlut_base*512:tlut_base*512+n_cyl*4] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for cyl in range(nr_cyls): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for side in range(nr_sides): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        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() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -53,18 +51,15 @@ class HFE(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     tdat += dat[d_off:d_off+d_nr] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     todo -= d_nr 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     offset += 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                hfe.track_list.append((len(tdat)*8, tdat)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hfe.to_track[cyl,side] = (len(tdat)*8, tdat) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return hfe 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def get_track(self, cyl, side): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if side >= self.nr_sides or cyl < self.start_cyl: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        off = cyl * self.nr_sides + side 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if off >= len(self.track_list): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (cyl,side) not in self.to_track: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        bitlen, rawbytes = self.track_list[off] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bitlen, rawbytes = self.to_track[cyl,side] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         tdat = bitarray(endian='little') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         tdat.frombytes(rawbytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         track = MasterTrack( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -73,22 +68,52 @@ class HFE(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return track 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def append_track(self, track): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def emit_track(self, cyl, side, track): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         raw = RawTrack(clock = 5e-4 / self.bitrate, data = track) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         bits, _ = raw.get_revolution(0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         bits.bytereverse() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.track_list.append((len(bits), bits.tobytes())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # We dynamically build the Track-LUT and -Data arrays. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tlut = bytearray() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tdat = bytearray() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Stuff real data into the image. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        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: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # Dummy data for empty cylinders. Assumes 300RPM. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                nr_bytes = 100 * self.bitrate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                tlut += struct.pack("<2H", len(tdat)//512 + 2, nr_bytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                tdat += bytes([0x88] * (nr_bytes+0x1ff & ~0x1ff)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # At least one side of this cylinder is populated. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                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))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Construct the image header. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        n_cyl = self.start_cyl + len(self.track_list) // self.nr_sides 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         header = struct.pack("<8s4B2H2BH", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              b"HXCPICFE", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              n_cyl, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             self.nr_sides, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             n_side, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              0xff, # unknown encoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              self.bitrate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              0,    # rpm (unused) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -96,28 +121,6 @@ class HFE(Image): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              1,    # rsvd 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              1)    # track list offset 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # We dynamically build the Track-LUT and -Data arrays. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        tlut = bytearray() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        tdat = bytearray() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # Dummy data for unused initial cylinders. Assumes 300RPM. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for i in range(self.start_cyl): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            nr_bytes = 100 * self.bitrate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            tlut += struct.pack("<2H", len(tdat)//512 + 2, nr_bytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            tdat += bytes([0x88] * (nr_bytes+0x1ff & ~0x1ff)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # Stuff real data into the image. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for i in range(0, len(self.track_list), self.nr_sides): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            bc = [self.track_list[i], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  self.track_list[i+1] if self.nr_sides > 1 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))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Pad the header and TLUT to 512-byte blocks. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         header += bytes([0xff] * (0x200 - len(header))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         tlut += bytes([0xff] * (0x200 - len(tlut))) 
			 |