adf.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. # greaseweazle/image/adf.py
  2. #
  3. # Written & released by Keir Fraser <keir.xen@gmail.com>
  4. #
  5. # This is free and unencumbered software released into the public domain.
  6. # See the file COPYING for more details, or visit <http://unlicense.org>.
  7. from greaseweazle import error
  8. import greaseweazle.codec.amiga.amigados as amigados
  9. from .image import Image
  10. from greaseweazle.codec import formats
  11. class ADF(Image):
  12. default_format = 'amiga.amigados'
  13. def __init__(self, name, fmt):
  14. self.to_track = dict()
  15. error.check(fmt is not None and fmt.adf_compatible, """\
  16. ADF image requires compatible format specifier
  17. Compatible formats:\n%s"""
  18. % formats.print_formats(lambda k, v: v.adf_compatible))
  19. self.filename = name
  20. self.fmt = fmt
  21. @classmethod
  22. def from_file(cls, name, fmt):
  23. with open(name, "rb") as f:
  24. dat = f.read()
  25. adf = cls(name, fmt)
  26. while True:
  27. nsec = fmt.fmt.nsec
  28. error.check((len(dat) % (2*nsec*512)) == 0, "Bad ADF image length")
  29. ncyl = len(dat) // (2*nsec*512)
  30. if ncyl < 90:
  31. break
  32. error.check(nsec == 11, "Bad ADF image length")
  33. fmt = adf.fmt = formats.Format_Amiga_AmigaDOS_HD()
  34. pos = 0
  35. for t in fmt.max_tracks:
  36. tnr = t.cyl*2 + t.head
  37. ados = fmt.fmt(t.cyl, t.head)
  38. pos += ados.set_adf_track(dat[pos:])
  39. adf.to_track[tnr] = ados
  40. return adf
  41. @classmethod
  42. def to_file(cls, name, fmt=None):
  43. return cls(name, fmt)
  44. def get_track(self, cyl, side):
  45. tnr = cyl * 2 + side
  46. if not tnr in self.to_track:
  47. return None
  48. return self.to_track[tnr].raw_track()
  49. def emit_track(self, cyl, side, track):
  50. tnr = cyl * 2 + side
  51. self.to_track[tnr] = track
  52. def get_image(self):
  53. tdat = bytearray()
  54. ntracks = max(self.to_track, default=0) + 1
  55. for tnr in range(ntracks):
  56. t = self.to_track[tnr] if tnr in self.to_track else None
  57. if t is not None and hasattr(t, 'get_adf_track'):
  58. tdat += t.get_adf_track()
  59. elif tnr < 160:
  60. # Pad empty/damaged tracks.
  61. tdat += amigados.bad_sector * self.fmt.fmt.nsec
  62. else:
  63. # Do not extend past 160 tracks unless there is data.
  64. break
  65. if ntracks < 160:
  66. tdat += amigados.bad_sector * self.fmt.fmt.nsec * (160 - ntracks)
  67. return tdat
  68. # Local variables:
  69. # python-indent: 4
  70. # End: