Pasti file Reader-Writer  1.0
Pasti files
PastiRead.cs
Go to the documentation of this file.
1 
26 using System;
27 using System.Diagnostics;
28 using System.IO;
29 using System.Windows.Controls;
30 using System.Windows.Media;
31 
32 namespace Pasti {
36  public class PastiReader {
37  TextBox _infoBox;
38 
43  public PastiReader(TextBox tb) {
44  _infoBox = tb;
45  }
46 
50  public enum PastiStatus {
52  Ok = 0,
59  }
60 
61 
68  public PastiStatus readPasti(string fileName, Floppy fd) {
69  FileStream fs;
70  try {
71  fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
72  }
73  catch (Exception exc) {
74  Console.WriteLine("Error: {0}", exc.Message);
75  return PastiStatus.FileNotFound;
76  }
77 
78  // read file into buffer
79  byte[] sbuf = new byte[fs.Length];
80  int bytes = fs.Read(sbuf, 0, (int)fs.Length);
81  Debug.Assert(bytes == fs.Length); // should be same
82  fs.Close();
83  PastiStatus status = decodePasti(sbuf, fd);
84  return status;
85  }
86 
87 
94  private PastiStatus decodePasti(byte[] buffer, Floppy fd) {
95  uint bpos = 0;
96  uint startPos = 0;
97  uint maxBufPos = 0;
98 
99  startPos = bpos;
100  FileDesc file = new FileDesc();
101  // Read File Descriptor
102  file.pastiFileId += readChar(buffer, ref bpos);
103  file.pastiFileId += readChar(buffer, ref bpos);
104  file.pastiFileId += readChar(buffer, ref bpos);
105  file.pastiFileId += readChar(buffer, ref bpos);
106  file.version = readUInt16(buffer, ref bpos);
107  file.tool = readUInt16(buffer, ref bpos);
108  file.reserved_1 = readUInt16(buffer, ref bpos);
109  file.trackCount = readByte(buffer, ref bpos);
110  file.revision = readByte(buffer, ref bpos);
111  file.reserved_2 = readUInt32(buffer, ref bpos);
112 
113  if (file.pastiFileId != "RSY\0")
114  return PastiStatus.NotPastiFile;
115  if (file.version != 3)
116  return PastiStatus.UnsupportedVersion;
117 
118  _infoBox.Clear();
119  _infoBox.FontFamily = new FontFamily("Consolas");
120  _infoBox.FontSize = 14;
121  _infoBox.AppendText(file.ToString());
122  _infoBox.AppendText(String.Format(" - ({0}-{1})\n", startPos, bpos - 1));
123  _infoBox.ScrollToHome();
124 
125  //fd.tracks = new Track[file.trackCount]; // create an array of track
126  fd.tracks = new Track[85, 2];
127  //fd.trackCount = file.trackCount; // store the number of tracks
128  //fd.version = (byte)(file.version * 10 + file.revision);
129  //fd.tool = file.tool;
130 
131  TrackDesc td = new TrackDesc();
132  for (int tnum = 0; tnum < file.trackCount; tnum++) {
133  uint track_record_start = bpos;
134  startPos = bpos;
135  Debug.Assert((startPos % 2) == 0, "Track Descriptor not word aligned", String.Format("Address = {0}", startPos));
136  // Read Track Descriptors
137  td.recordSize = readUInt32(buffer, ref bpos);
138  td.fuzzyCount = readUInt32(buffer, ref bpos);
139  td.sectorCount = readUInt16(buffer, ref bpos);
140  td.trackFlags = readUInt16(buffer, ref bpos);
141  td.trackLength = readUInt16(buffer, ref bpos);
142  td.trackNumber = readByte(buffer, ref bpos);
143  td.trackType = readByte(buffer, ref bpos);
144  maxBufPos = bpos;
145  int track = td.trackNumber & 0x7F;
146  int side = (td.trackNumber & 0x80) >> 7;
147 
148  _infoBox.AppendText(td.ToString());
149  _infoBox.AppendText(String.Format(" ({0}-{1})\n", startPos, bpos - 1));
150 
151  fd.tracks[track, side] = new Track();
152 
153  // create array of sector for this track
154  fd.tracks[track, side].sectors = new Sector[td.sectorCount];
155  fd.tracks[track, side].sectorCount = td.sectorCount;
156  fd.tracks[track, side].byteCount = td.trackLength;
157  fd.tracks[track, side].side = (uint)(td.trackNumber >> 7);
158  fd.tracks[track, side].number = (uint)(td.trackNumber & 0x7F);
159 
160  // read sector descriptors if specified
161  if ((td.trackFlags & TrackDesc.TRK_SECT_DESC) != 0) {
162  SectorDesc[] sectors = new SectorDesc[td.sectorCount];
163  for (int snum = 0; snum < td.sectorCount; snum++) {
164  sectors[snum] = new SectorDesc();
165  startPos = bpos;
166 
167  // read sector descriptor
168  sectors[snum].dataOffset = readUInt32(buffer, ref bpos);
169  sectors[snum].bitPosition = readUInt16(buffer, ref bpos);
170  sectors[snum].readTime = readUInt16(buffer, ref bpos);
171  sectors[snum].id.track = readByte(buffer, ref bpos);
172  sectors[snum].id.side = readByte(buffer, ref bpos);
173  sectors[snum].id.number = readByte(buffer, ref bpos);
174  sectors[snum].id.size = readByte(buffer, ref bpos);
175  sectors[snum].id.crc = readUInt16(buffer, ref bpos);
176  sectors[snum].fdcFlags = readByte(buffer, ref bpos);
177  sectors[snum].reserved = readByte(buffer, ref bpos);
178 
179  _infoBox.AppendText(sectors[snum].ToString());
180  _infoBox.AppendText(String.Format(" ({0}-{1})\n", startPos, bpos - 1));
181 
182  fd.tracks[track, side].sectors[snum] = new Sector();
183  fd.tracks[track, side].sectors[snum].fdcFlags = sectors[snum].fdcFlags;
184  fd.tracks[track, side].sectors[snum].bitPosition = sectors[snum].bitPosition;
185  fd.tracks[track, side].sectors[snum].readTime = sectors[snum].readTime;
186  fd.tracks[track, side].sectors[snum].id = sectors[snum].id;
187  fd.tracks[track, side].sectors[snum].fdcFlags = sectors[snum].fdcFlags;
188  } // for all sectors
189 
190  byte[] fuzzyMask = null;
191  // if necessary read fuzzy bytes
192  if (td.fuzzyCount != 0) {
193  startPos = bpos;
194  fuzzyMask = new byte[td.fuzzyCount];
195  for (int i = 0; i < td.fuzzyCount; i++)
196  fuzzyMask[i] = readByte(buffer, ref bpos);
197  _infoBox.AppendText(String.Format(" Reading Fuzzy {0} bytes ({1}-{2})\n", td.fuzzyCount, startPos, bpos - 1));
198  }
199 
200  // the track data are located after the sector descriptor records & fuzzy record
201  uint track_data_start = bpos; // store the position of data in track record
202  _infoBox.AppendText(String.Format(" Start of Track data {0}\n", track_data_start));
203 
204  // read track data if specified
205  if ((td.trackFlags & TrackDesc.TRK_IMAGE) != 0) {
206  // track with sync offset
207  startPos = bpos;
208  // read sync if provided
209  if ((td.trackFlags & TrackDesc.TRK_SYNC) != 0)
210  fd.tracks[track, side].firstSyncOffset = readUInt16(buffer, ref bpos);
211  else
212  fd.tracks[track, side].firstSyncOffset = 0;
213  // read track data size
214  fd.tracks[track, side].byteCount = readUInt16(buffer, ref bpos);
215  // read track data
216  fd.tracks[track, side].trackData = new byte[fd.tracks[track, side].byteCount];
217  for (int i = 0; i < fd.tracks[track, side].byteCount; i++)
218  fd.tracks[track, side].trackData[i] = readByte(buffer, ref bpos);
219  // seems like we are reading even number
220  maxBufPos = Math.Max(maxBufPos, bpos + bpos % 2);
221  fd.tracks[track, side].standardTrack = false;
222  _infoBox.AppendText(String.Format(" Reading Track Image {0}{1} bytes SyncPos={2} ({3}-{4})\n",
223  fd.tracks[track, side].byteCount + (((td.trackFlags & TrackDesc.TRK_SYNC) != 0) ? 4 : 2), (bpos % 2 != 0) ? "(+1)" : "",
224  fd.tracks[track, side].firstSyncOffset, startPos, bpos + (bpos % 2) - 1));
225  } // read track_data
226 
227  // read all sectors data
228  bool bitWidth = false;
229  for (int snum = 0; snum < td.sectorCount; snum++) {
230  if (((sectors[snum].fdcFlags & SectorDesc.BIT_WIDTH) != 0) && (file.revision == 2))
231  bitWidth = true;
232 
233  // create sector buffer and read data if necessary
234  if ((sectors[snum].fdcFlags & SectorDesc.SECT_RNF) == 0) {
235  fd.tracks[track, side].sectors[snum].sectorData = new byte[128 << sectors[snum].id.size];
236  bpos = track_data_start + sectors[snum].dataOffset;
237  startPos = bpos;
238  for (int i = 0; i < 128 << sectors[snum].id.size; i++)
239  fd.tracks[track, side].sectors[snum].sectorData[i] = readByte(buffer, ref bpos);
240  maxBufPos = Math.Max(maxBufPos, bpos);
241  _infoBox.AppendText(String.Format(" Reading Sector {0} {1} bytes ({2}-{3}) {4}\n",
242  fd.tracks[track, side].sectors[snum].id.number, 128 << sectors[snum].id.size, startPos, bpos - 1,
243  (((td.trackFlags & TrackDesc.TRK_IMAGE) != 0) && (sectors[snum].dataOffset < fd.tracks[track, side].byteCount)) ? " in Track Image" : ""));
244  } // read sector data
245  } // for all sectors
246 
247  // if we have timing record we read
248  ushort[] timing = null;
249  if (bitWidth) {
250  bpos = maxBufPos;
251  startPos = bpos;
252  ushort timingFlags = readUInt16(buffer, ref bpos);
253  ushort timingSize = readUInt16(buffer, ref bpos);
254  int entries = (timingSize - 4) / 2;
255  timing = new ushort[entries];
256  for (int i = 0; i < entries; i++) {
257  // Big Indian value
258  timing[i] = (ushort)(readByte(buffer, ref bpos) << 8);
259  timing[i] = readByte(buffer, ref bpos);
260  }
261  maxBufPos = Math.Max(maxBufPos, bpos);
262  _infoBox.AppendText(String.Format(" Reading Timing {0} bytes Flag={1} ({2}-{3})\n", timingSize, timingFlags, startPos, bpos - 1));
263  } // sector has timing data
264 
265  // now we transfer the fuzzy bytes and timing bytes if necessary
266  int startFuzzy = 0;
267  int startTiming = 0;
268  for (int snum = 0; snum < td.sectorCount; snum++) {
269  // fuzzy bytes
270  if ((fd.tracks[track, side].sectors[snum].fdcFlags & SectorDesc.FUZZY_BITS) != 0) {
271  int fsize = 128 << sectors[snum].id.size;
272  fd.tracks[track, side].sectors[snum].fuzzyData = new byte[fsize];
273  for (int i = 0; i < fsize; i++)
274  fd.tracks[track, side].sectors[snum].fuzzyData[i] = fuzzyMask[i + startFuzzy];
275  startFuzzy += fsize;
276  _infoBox.AppendText(String.Format(" Transferring {0} Fuzzy bytes to sect {1}\n", fsize, fd.tracks[track, side].sectors[snum].id.number));
277  }
278  // timing bytes
279  if ((sectors[snum].fdcFlags & SectorDesc.BIT_WIDTH) != 0) {
280  int tsize = (128 << sectors[snum].id.size) / 16;
281  fd.tracks[track, side].sectors[snum].timmingData = new ushort[tsize];
282  if (file.revision == 2) {
283  for (int i = 0; i < tsize; i++)
284  fd.tracks[track, side].sectors[snum].timmingData[i] = timing[i + startTiming];
285  startTiming += tsize;
286  _infoBox.AppendText(String.Format(" Transferring {0} Timing values to sect {1}\n", tsize, fd.tracks[track, side].sectors[snum].id.number));
287  } // revision == 2 => read timing from file
288  else {
289  for (int i = 0; i < tsize; i++) {
290  if (i < (tsize / 4)) fd.tracks[track, side].sectors[snum].timmingData[i] = 127;
291  else if (i < (tsize / 2)) fd.tracks[track, side].sectors[snum].timmingData[i] = 133;
292  else if (i < ((3 * tsize) / 2)) fd.tracks[track, side].sectors[snum].timmingData[i] = 121;
293  else fd.tracks[track, side].sectors[snum].timmingData[i] = 127;
294  }
295  } // if revision != 2 => we simulate with a table
296  }
297  }
298  if (timing != null)
299  Debug.Assert(timing.Length == startTiming, "invalid timing size");
300  if (fuzzyMask != null)
301  Debug.Assert(fuzzyMask.Length == startFuzzy, "invalid fuzzy size");
302  } // TRK_SECT provided
303 
304  else {
305  // read all standard sectors
306  for (int snum = 0; snum < td.sectorCount; snum++) {
307  startPos = bpos;
308  fd.tracks[track, side].sectors[snum] = new Sector();
309  fd.tracks[track, side].sectors[snum].sectorData = new byte[512];
310  for (int i = 0; i < 512; i++)
311  fd.tracks[track, side].sectors[snum].sectorData[i] = readByte(buffer, ref bpos);
312 
313  fd.tracks[track, side].sectors[snum].fdcFlags = 0;
314  fd.tracks[track, side].sectors[snum].bitPosition = 0;
315  fd.tracks[track, side].sectors[snum].readTime = 0;
316  fd.tracks[track, side].sectors[snum].fuzzyData = null;
317  fd.tracks[track, side].sectors[snum].timmingData = null;
318  fd.tracks[track, side].sectors[snum].id.track = (byte)(td.trackNumber & 0x7F);
319  fd.tracks[track, side].sectors[snum].id.side = (byte)(((td.trackNumber & 0x80) == 0x80) ? 1 : 0);
320  fd.tracks[track, side].sectors[snum].id.number = (byte)snum;
321  fd.tracks[track, side].sectors[snum].id.crc = 0;
322  _infoBox.AppendText(String.Format(" Standard Sector {0} {1} bytes ({2}-{3})\n", snum, 512, startPos, bpos));
323  maxBufPos = Math.Max(maxBufPos, bpos);
324  } // read all sector
325  } // standard non protected sectors
326 
327  // we set record size to even value
328  maxBufPos += maxBufPos % 2;
329 
330  Debug.Assert(maxBufPos == track_record_start + td.recordSize, "Invalid Track Size",
331  String.Format("Track {0} Current pointer position = {1} next track = {2}", td.trackNumber, bpos, track_record_start + td.recordSize));
332  bpos = track_record_start + td.recordSize;
333  } // for all tracks
334 
335  return PastiStatus.Ok;
336 
337  } // pasti/pasti file
338 
339 
340  private static uint readUInt32(byte[] buf, ref uint pos) {
341  uint val = (uint)buf[pos] + (uint)(buf[pos + 1] << 8) + (uint)(buf[pos + 2] << 16) + (uint)(buf[pos + 3] << 24);
342  pos += 4;
343  return val;
344  }
345 
346 
347  private static ushort readUInt16(byte[] buf, ref uint pos) {
348  ushort val = (ushort)buf[pos];
349  val += (ushort)(buf[pos + 1] << 8);
350  pos += 2;
351  return val;
352  }
353 
354 
355  private static byte readByte(byte[] buf, ref uint pos) {
356  return buf[pos++];
357  }
358 
359 
360  private static char readChar(byte[] buf, ref uint pos) {
361  return (char)buf[pos++];
362  }
363 
364  }
365 
366 }
The reader class
Definition: PastiRead.cs:36
Pasti File Track Descriptor
Definition: PastiStruct.cs:79
Track[,] tracks
Array of Tracks
Definition: FloppyStruct.cs:90
Pasti File Header Descriptor
Definition: PastiStruct.cs:40
override string ToString()
Override ToString() to display Track header information
Definition: PastiStruct.cs:128
ushort trackFlags
This field contain bit-mask flags that provide information about the content of the track record as f...
Definition: PastiStruct.cs:106
byte reserved
Reserved (should be 0x00)
Definition: PastiStruct.cs:213
Could not open file for reading or file not found
ushort crc
CRC Value from address field
Definition: PastiStruct.cs:151
override string ToString()
Override ToString() to display File header information
Definition: PastiStruct.cs:69
byte trackType
track image type (not used)
Definition: PastiStruct.cs:112
byte track
Track number from address field
Definition: PastiStruct.cs:143
uint sectorCount
Number of sectors for this track
Definition: FloppyStruct.cs:58
Contains information about one sector
Definition: FloppyStruct.cs:34
ushort sectorCount
number of sectors in the track
Definition: PastiStruct.cs:92
uint fuzzyCount
number of bytes in the fuzzy mask
Definition: PastiStruct.cs:87
ushort readTime
This field contains either zero or the read time for the sector data block.
Definition: PastiStruct.cs:189
File read correctly
ushort bitPosition
position in the track of the sector address field in bits
Definition: FloppyStruct.cs:42
const byte TRK_SECT_DESC
The track record contains sectorCount SectDesc
Definition: PastiStruct.cs:122
ushort bitPosition
This field store the position in number of bits of this sector address block from the index...
Definition: PastiStruct.cs:182
byte size
Size value from address field
Definition: PastiStruct.cs:149
PastiStatus readPasti(string fileName, Floppy fd)
Read a Pasti file and fills the Floppy structure
Definition: PastiRead.cs:68
PastiReader(TextBox tb)
The Pasti reader constructor
Definition: PastiRead.cs:43
byte[] trackData
buffer for the track data if necessary
Definition: FloppyStruct.cs:61
const byte SECT_RNF
RNF or Seek error
Definition: PastiStruct.cs:219
bool standardTrack
The track follow the Atari standard
Definition: FloppyStruct.cs:82
Contains information about one Track
Definition: FloppyStruct.cs:53
byte trackCount
Number of track records
Definition: PastiStruct.cs:56
ushort trackLength
length of the track in number of bytes. Usually around 6250 bytes.
Definition: PastiStruct.cs:108
ushort version
File version number: Should be equal to 3.
Definition: PastiStruct.cs:46
Contains information about a complete Floppy disk
Definition: FloppyStruct.cs:88
byte trackNumber
Bit 7 contains the side (0 or 1) and bits 6-0 contain the track number (usually 0 to 79)...
Definition: PastiStruct.cs:110
IDField id
Address field content
Definition: FloppyStruct.cs:46
Pasti File Sector Descriptor
Definition: PastiStruct.cs:173
ushort firstSyncOffset
First sync byte offset: This is the offset in byte of the first 0xA1 sync byte found in the track...
Definition: FloppyStruct.cs:65
byte number
Sector number from address field
Definition: PastiStruct.cs:147
uint byteCount
Number of bytes in the track
Definition: FloppyStruct.cs:68
uint number
track number
Definition: FloppyStruct.cs:71
The header in the file is not RSY
Sector[] sectors
Array of Sectors
Definition: FloppyStruct.cs:55
ushort readTime
read time of the track in ms or 0 if standard sector
Definition: FloppyStruct.cs:44
byte[] sectorData
buffer for the sector data
Definition: FloppyStruct.cs:36
IDField id
Address field of sector (refer to the Address structure)
Definition: PastiStruct.cs:191
ushort tool
Tool used to create image
Definition: PastiStruct.cs:52
uint recordSize
Total size of this track record.
Definition: PastiStruct.cs:83
byte revision
revision number of the file.
Definition: PastiStruct.cs:61
ushort[] timmingData
buffer for timing bytes if necessary
Definition: FloppyStruct.cs:40
byte fdcFlags
This field contains a mixture of the FDC status, as it would have been read by the WD1772...
Definition: PastiStruct.cs:211
uint reserved_2
Reserved
Definition: PastiStruct.cs:63
string pastiFileId
Identify a Pasti file and should be equal to the null terminated string “RSY”
Definition: PastiStruct.cs:44
uint dataOffset
Offset of sector data inside the track record
Definition: PastiStruct.cs:179
byte side
Head number from address field
Definition: PastiStruct.cs:145
byte[] fuzzyData
buffer for fuzzy mask bytes if necessary
Definition: FloppyStruct.cs:38
uint side
track side
Definition: FloppyStruct.cs:74
ushort reserved_1
Reserved
Definition: PastiStruct.cs:54
const byte BIT_WIDTH
Sector has bit width variation
Definition: PastiStruct.cs:227
byte fdcFlags
Status returned by the FDC
Definition: FloppyStruct.cs:48
PastiStatus
Status returned when reading Pasti file
Definition: PastiRead.cs:50