コード例 #1
0
ファイル: edsk.py プロジェクト: troed/Greaseweazle
 def _build_8k_track(sectors):
     if len(sectors) != 1:
         return None
     c, h, r, n, errs, data = sectors[0]
     if n != 6:
         return None
     if errs.id_crc_error or errs.data_not_found or not errs.data_crc_error:
         return None
     # Magic longtrack value is for Coin-Op Hits. Taken from SAMdisk.
     if len(data) > 6307:
         data = data[:6307]
     track = EDSKTrack()
     t = track.bytes
     # Post-index gap
     t += mfm.encode(bytes([track.gapbyte] * 16))
     # IAM
     t += mfm.encode(bytes(track.gap_presync))
     t += mfm.iam_sync_bytes
     t += mfm.encode(bytes([mfm.IBM_MFM.IAM]))
     t += mfm.encode(bytes([track.gapbyte] * 16))
     # IDAM
     t += mfm.encode(bytes(track.gap_presync))
     t += mfm.sync_bytes
     am = bytes([0xa1, 0xa1, 0xa1, mfm.IBM_MFM.IDAM, c, h, r, n])
     crc = mfm.crc16.new(am).crcValue
     am += struct.pack('>H', crc)
     t += mfm.encode(am[3:])
     t += mfm.encode(bytes([track.gapbyte] * track.gap_2))
     # DAM
     t += mfm.encode(bytes(track.gap_presync))
     t += mfm.sync_bytes
     dmark = (mfm.IBM_MFM.DDAM if errs.deleted_dam else mfm.IBM_MFM.DAM)
     am = bytes([0xa1, 0xa1, 0xa1, dmark]) + data
     t += mfm.encode(am[3:])
     return track
コード例 #2
0
    def from_file(cls, name):

        with open(name, "rb") as f:
            dat = f.read()

        edsk = cls()

        sig, creator, ncyls, nsides, track_sz = struct.unpack(
            '<34s14s2BH', dat[:52])
        if sig[:8] == b'MV - CPC':
            extended = False
        elif sig[:16] == b'EXTENDED CPC DSK':
            extended = True
        else:
            raise error.Fatal('Unrecognised CPC DSK file: bad signature')

        if extended:
            track_sizes = list(dat[52:52+ncyls*nsides])
            track_sizes = list(map(lambda x: x*256, track_sizes))
        else:
            track_sizes = [track_sz] * (ncyls * nsides)

        o = 256 # skip disk header and track-size table
        for track_size in track_sizes:
            if track_size == 0:
                continue
            sig, cyl, head, sec_sz, nsecs, gap_3, filler = struct.unpack(
                '<12s4x2B2x4B', dat[o:o+24])
            error.check(sig == b'Track-Info\r\n',
                        '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 = track.bytes
                # Post-index gap
                t += mfm.encode(bytes([track.gapbyte] * track.gap_4a))
                # IAM
                t += mfm.encode(bytes(track.gap_presync))
                t += mfm.iam_sync_bytes
                t += mfm.encode(bytes([mfm.IBM_MFM.IAM]))
                t += mfm.encode(bytes([track.gapbyte] * track.gap_1))
                sh = dat[o+24:o+24+8*nsecs]
                data_pos = o + 256 # skip track header and sector-info table
                clippable, ngap3, sectors, idam_included = 0, 0, [], False
                while sh:
                    c, h, r, n, stat1, stat2, data_size = struct.unpack(
                        '<6BH', sh[:8])
                    sh = sh[8:]
                    native_size = mfm.sec_sz(n)
                    weak = []
                    errs = SectorErrors(stat1, stat2)
                    num_copies = 0 if errs.data_not_found else 1
                    if not extended:
                        data_size = mfm.sec_sz(sec_sz)
                    sec_data = dat[data_pos:data_pos+data_size]
                    data_pos += data_size
                    if (extended
                        and data_size > native_size
                        and errs.data_crc_error
                        and (data_size % native_size == 0
                             or data_size == 49152)):
                        num_copies = (3 if data_size == 49152
                                      else data_size // native_size)
                        data_size //= num_copies
                        weak = cls().find_weak_ranges(sec_data, data_size)
                        sec_data = sec_data[:data_size]
                    sectors.append((c,h,r,n,errs,sec_data))
                    # IDAM
                    if not idam_included:
                        t += mfm.encode(bytes(track.gap_presync))
                        t += mfm.sync_bytes
                        am = bytes([0xa1, 0xa1, 0xa1, mfm.IBM_MFM.IDAM,
                                    c, h, r, n])
                        crc = mfm.crc16.new(am).crcValue
                        if errs.id_crc_error:
                            crc ^= 0x5555
                        am += struct.pack('>H', crc)
                        t += mfm.encode(am[3:])
                        t += mfm.encode(bytes([track.gapbyte] * track.gap_2))
                    # DAM
                    gap_included, idam_included = False, False
                    if errs.id_crc_error or errs.data_not_found:
                        continue
                    t += mfm.encode(bytes(track.gap_presync))
                    t += mfm.sync_bytes
                    track.weak += [((s+len(t)//2+1)*16, n*16) for s,n in weak]
                    dmark = (mfm.IBM_MFM.DDAM if errs.deleted_dam
                             else mfm.IBM_MFM.DAM)
                    if errs.data_crc_error:
                        if sh:
                            # 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]*8))
                        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 it includes pre-sync 00 bytes
                        if (sec_data[-13] != 0
                            and all([v==0 for v in sec_data[-12:]])):
                            # Includes next pre-sync: Clip it.
                            sec_data = sec_data[:-12]
                        if sh:
                            # Look for next IDAM
                            idam = bytes([0]*12 + [0xa1]*3 + [mfm.IBM_MFM.IDAM]
                                         + list(sh[:4]))
                            idx = sec_data.find(idam)
                            if idx > native_size:
                                # Sector data includes next IDAM. Output it
                                # here and skip it on next iteration.
                                t += mfm.encode(bytes([dmark]))
                                t += mfm.encode(sec_data[:idx+12])
                                t += mfm.sync_bytes
                                t += mfm.encode(sec_data[idx+12+3:])
                                idam_included = True
                                continue
                        # Long data includes CRC and GAP
                        gap_included = True
                    if gap_included:
                        t += mfm.encode(bytes([dmark]))
                        t += mfm.encode(sec_data)
                        continue
                    am = bytes([0xa1, 0xa1, 0xa1, dmark]) + sec_data
                    crc = mfm.crc16.new(am).crcValue
                    if errs.data_crc_error:
                        crc ^= 0x5555
                    am += struct.pack('>H', crc)
                    t += mfm.encode(am[3:])
                    if sh:
                        # GAP3 for all but last sector
                        t += mfm.encode(bytes([track.gapbyte] * gap_3))
                        ngap3 += 1

                # Special track handlers
                special_track = cls()._build_8k_track(sectors)
                if special_track is None:
                    special_track = cls()._build_kbi19_track(sectors)
                if special_track is not None:
                    track = special_track
                    break

                # 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

                # Some EDSK tracks with Bad CRC contain a raw dump following
                # the DAM. This can usually be clipped.
                if clippable and not bad_crc_clip_data:
                    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*ngap3)*16))
                #print('EDSK: GAP3 reduced (%d -> %d)' % (gap_3, new_gap_3))
                gap_3 = new_gap_3

            # Pre-index gap
            track.verify_len = len(track.bytes)*8
            tracklen = int((track.time_per_rev / track.clock) / 16)
            gap = max(40, tracklen - len(t)//2)
            track.bytes += mfm.encode(bytes([track.gapbyte] * gap))

            # Add the clock buts
            track.bits = bitarray(endian='big')
            track.bits.frombytes(mfm.mfm_encode(track.bytes))

            # Register the track
            edsk.to_track[cyl,head] = track
            o += track_size

        return edsk
コード例 #3
0
 def addcrc(t,n):
     crc = mfm.crc16.new(mfm.decode(t[-n*2:])).crcValue
     t += mfm.encode(struct.pack('>H', crc))
コード例 #4
0
 def _build_kbi19_track(sectors):
     ids = [0,1,4,7,10,13,16,2,5,8,11,14,17,3,6,9,12,15,18]
     if len(sectors) != len(ids):
         return None
     for s,id in zip(sectors,ids):
         c,h,r,n,_,_ = s
         if r != id or n != 2:
             return None
     def addcrc(t,n):
         crc = mfm.crc16.new(mfm.decode(t[-n*2:])).crcValue
         t += mfm.encode(struct.pack('>H', crc))
     track = EDSKTrack()
     t = track.bytes
     # Post-index gap
     t += mfm.encode(bytes([track.gapbyte] * 64))
     # IAM
     t += mfm.encode(bytes(track.gap_presync))
     t += mfm.iam_sync_bytes
     t += mfm.encode(bytes([mfm.IBM_MFM.IAM]))
     t += mfm.encode(bytes([track.gapbyte] * 50))
     for idx, s in enumerate(sectors):
         c,h,r,n,errs,data = s
         # IDAM
         t += mfm.encode(bytes(track.gap_presync))
         t += mfm.sync_bytes
         t += mfm.encode(bytes([mfm.IBM_MFM.IDAM, c, h, r, n]))
         addcrc(t, 8)
         if r == 0:
             t += mfm.encode(bytes([track.gapbyte] * 17))
             t += mfm.encode(b' KBI ')
         else:
             t += mfm.encode(bytes([track.gapbyte] * 8))
             t += mfm.encode(b' KBI ')
             t += mfm.encode(bytes([track.gapbyte] * 9))
         # DAM
         t += mfm.encode(bytes(track.gap_presync))
         t += mfm.sync_bytes
         dmark = (mfm.IBM_MFM.DDAM if errs.deleted_dam
                  else mfm.IBM_MFM.DAM)
         t += mfm.encode(bytes([dmark]))
         if idx%3 != 0:
             t += mfm.encode(data[:61])
         elif r == 0:
             t += mfm.encode(data[:512])
             addcrc(t,516)
         else:
             t += mfm.encode(data[0:0x10e])
             addcrc(t,516)
             t += mfm.encode(data[0x110:0x187])
             addcrc(t,516)
             t += mfm.encode(data[0x189:0x200])
             addcrc(t,516)
             t += mfm.encode(bytes([track.gapbyte] * 80))
     return track