Browse Source

edsk: Support clipping over-long data region if it runs into next sector.

Keir Fraser 4 years ago
parent
commit
0828224662
1 changed files with 53 additions and 19 deletions
  1. 53 19
      scripts/greaseweazle/image/edsk.py

+ 53 - 19
scripts/greaseweazle/image/edsk.py

@@ -206,6 +206,7 @@ class EDSK(Image):
                         'EDSK: Missing track header')
             error.check((cyl, head) not in edsk.to_track,
                         'EDSK: Track specified twice')
+            bad_crc_clip_data = False
             while True:
                 track = EDSKTrack()
                 t = bytes()
@@ -218,6 +219,7 @@ class EDSK(Image):
                 t += mfm.encode(bytes([track.gapbyte] * track.gap_1))
                 secs = dat[o+24:o+24+8*nsecs]
                 data_pos = o + 256 # skip track header and sector-info table
+                clippable, ngap3 = 0, 0
                 while secs:
                     c, h, r, n, stat1, stat2, data_size = struct.unpack(
                         '<6BH', secs[:8])
@@ -240,9 +242,6 @@ class EDSK(Image):
                         data_size //= num_copies
                         weak = cls().find_weak_ranges(sec_data, data_size)
                         sec_data = sec_data[:data_size]
-                    if data_size < native_size:
-                        # Pad short data
-                        sec_data += bytes(native_size - data_size)
                     # IDAM
                     t += mfm.encode(bytes(track.gap_presync))
                     t += mfm.sync_bytes
@@ -262,35 +261,70 @@ class EDSK(Image):
                     track.weak += [((s+len(t)//2+4)*16, n*16) for s,n in weak]
                     dmark = (mfm.IBM_MFM.DDAM if errs.deleted_dam
                              else mfm.IBM_MFM.DAM)
-                    am = bytes([0xa1, 0xa1, 0xa1, dmark]) + sec_data
-                    if data_size > native_size:
-                        # Long data includes CRC and GAP
+                    gap_included = False
+                    if errs.data_crc_error:
+                        if secs:
+                            # Look for next IDAM
+                            idam = bytes([0]*12 + [0xa1]*3
+                                         + [mfm.IBM_MFM.IDAM])
+                            idx = sec_data.find(idam)
+                        else:
+                            # Last sector: Look for GAP3
+                            idx = sec_data.find(bytes([track.gapbyte]*16))
+                        if idx > 0:
+                            # 2 + gap_3 = CRC + GAP3 (because gap_included)
+                            clippable += data_size - idx + 2 + gap_3
+                            if bad_crc_clip_data:
+                                data_size = idx
+                                sec_data = sec_data[:data_size]
+                                gap_included = True
+                    elif data_size < native_size:
+                        # Pad short data
+                        sec_data += bytes(native_size - data_size)
+                    elif data_size > native_size:
+                        # Clip long data
                         if (sec_data[-13] != 0
                             and all([v==0 for v in sec_data[-12:]])):
                             # Includes next pre-sync: Clip it.
-                            am = am[:-12]
+                            sec_data = sec_data[:-12]
+                        # Long data includes CRC and GAP
+                        gap_included = True
+                    am = bytes([0xa1, 0xa1, 0xa1, dmark]) + sec_data
+                    if gap_included:
                         t += mfm.encode(am[3:])
-                        continue
-                    crc = mfm.crc16.new(am).crcValue
-                    if errs.data_crc_error:
-                        crc ^= 0x5555
-                    am += struct.pack('>H', crc)
-                    t += mfm.encode(am[3:])
-                    t += mfm.encode(bytes([track.gapbyte] * gap_3))
+                    else:
+                        crc = mfm.crc16.new(am).crcValue
+                        if errs.data_crc_error:
+                            crc ^= 0x5555
+                        am += struct.pack('>H', crc)
+                        t += mfm.encode(am[3:])
+                        if secs:
+                            # GAP3 for all but last sector
+                            t += mfm.encode(bytes([track.gapbyte] * gap_3))
+                            ngap3 += 1
 
-                # Some EDSK images have bogus GAP3 values. If the track is too
-                # long to comfortably fit in 300rpm at double density, shrink
-                # GAP3 as far as necessary.
+                # The track may be too long to fit: Check for overhang.
                 tracklen = int((track.time_per_rev / track.clock) / 16)
                 overhang = int(len(t)//2 - tracklen*0.99)
                 if overhang <= 0:
                     break
-                new_gap_3 = gap_3 - math.ceil(overhang / nsecs)
+
+                # Some EDSK tracks with Bad CRC contain a raw dump following
+                # the DAM. This can usually be clipped.
+                if clippable > overhang:
+                    bad_crc_clip_data = True
+                    continue
+
+                # Some EDSK images have bogus GAP3 values. Shrink it if
+                # necessary.
+                new_gap_3 = -1
+                if ngap3 != 0:
+                    new_gap_3 = gap_3 - math.ceil(overhang / ngap3)
                 error.check(new_gap_3 >= 0,
                             'EDSK: Track %d.%d is too long '
                             '(%d bits @ GAP3=%d; %d bits @ GAP3=0)'
                             % (cyl, head, len(t)*8, gap_3,
-                               (len(t)//2-gap_3*nsecs)*16))
+                               (len(t)//2-gap_3*ngap3)*16))
                 #print('EDSK: GAP3 reduced (%d -> %d)' % (gap_3, new_gap_3))
                 gap_3 = new_gap_3