/[projet1]/public/pc/tools/osdk/main/FloppyBuilder/Floppy.cpp
Defence Force logotype

Contents of /public/pc/tools/osdk/main/FloppyBuilder/Floppy.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1129 - (show annotations)
Sun May 11 09:17:25 2014 UTC (5 years, 7 months ago) by dbug
File size: 29263 byte(s)
Got the latest changes from Hialmar and Jylam, and made the Visual Studio build work again (hopefully did not break the Linux stuff)

Also some changes that were not committed yet:
FloppyBuilder 0.16 - 2014/04/06
- Added a mode where data can be extracted from an existing DSK file
- The parser now accepts quoted strings

1
2 #include "infos.h"
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <sstream>
7 #include <iostream>
8 #include <string.h>
9
10 #include <assert.h>
11
12 #include "Floppy.h"
13
14 #include "common.h"
15
16
17
18
19 FloppyHeader::FloppyHeader()
20 {
21 assert(sizeof(*this)==256);
22 memset(this,0,sizeof(*this));
23 }
24
25 FloppyHeader::~FloppyHeader()
26 {
27 }
28
29 bool FloppyHeader::IsValidHeader() const
30 {
31 if (memcmp(m_Signature,"MFM_DISK",8)!=0) return false;
32
33 int sideNumber=GetSideNumber();
34 if ((sideNumber<1) || (sideNumber>2)) return false;
35
36 int trackNumber=GetTrackNumber();
37 if ((trackNumber<30) || (trackNumber>82)) return false;
38
39 return true;
40 }
41
42
43 void FloppyHeader::Clear()
44 {
45 memset(this,0,sizeof(FloppyHeader));
46 }
47
48 void FloppyHeader::SetSignature(char signature[8])
49 {
50 memcpy(m_Signature,signature,8);
51 }
52
53
54 void FloppyHeader::SetSideNumber(int sideNumber)
55 {
56 m_Sides[0]=(sideNumber>>0)&255;
57 m_Sides[1]=(sideNumber>>8)&255;
58 m_Sides[2]=(sideNumber>>16)&255;
59 m_Sides[3]=(sideNumber>>24)&255;
60 }
61
62 int FloppyHeader::GetSideNumber() const
63 {
64 int sideNumber= ( ( ( ( (m_Sides[3]<<8) | m_Sides[2]) << 8 ) | m_Sides[1]) << 8 ) | m_Sides[0];
65 return sideNumber;
66 }
67
68
69 void FloppyHeader::SetTrackNumber(int trackNumber)
70 {
71 m_Tracks[0]=(trackNumber>>0)&255;
72 m_Tracks[1]=(trackNumber>>8)&255;
73 m_Tracks[2]=(trackNumber>>16)&255;
74 m_Tracks[3]=(trackNumber>>24)&255;
75 }
76
77 int FloppyHeader::GetTrackNumber() const
78 {
79 int trackNumber= ( ( ( ( (m_Tracks[3]<<8) | m_Tracks[2]) << 8 ) | m_Tracks[1]) << 8 ) | m_Tracks[0];
80 return trackNumber;
81 }
82
83 void FloppyHeader::SetGeometry(int geometry)
84 {
85 m_Geometry[0]=(geometry>>0)&255;
86 m_Geometry[1]=(geometry>>8)&255;
87 m_Geometry[2]=(geometry>>16)&255;
88 m_Geometry[3]=(geometry>>24)&255;
89 }
90
91 int FloppyHeader::GetGeometry() const
92 {
93 int geometry= ( ( ( ( (m_Geometry[3]<<8) | m_Geometry[2]) << 8 ) | m_Geometry[1]) << 8 ) | m_Geometry[0];
94 return geometry;
95 }
96
97 int FloppyHeader::FindNumberOfSectors(int& firstSectorOffset,int& sectorInterleave) const
98 {
99 firstSectorOffset=0;
100 sectorInterleave=0;
101
102 /*
103 Format of a track:
104 6400 bytes in total
105 - gap1: 72/12 bytes at the start of the track (with zeroes)
106 Then for each sector:
107 - ?: 4 bytes (A1 A1 A1 FE)
108 - track number: 1 byte (0-40-80...)
109 - side number: 1 byte (0-1)
110 - sector number: 1 byte (1-18-19)
111 - one: 1 byte (1)
112 - crc: 2 bytes (crc of the 8 previous bytes)
113 - gap2: 34 bytes (22xAE , 12x00)
114 - ?: 4 bytes (A1 A1 A1 FB)
115 - data: 256 bytes
116 - crc: 2 bytes (crc of the 256+4 previous bytes)
117 - gap3: 50/46 bytes
118 */
119 unsigned char* trackDataStart=(unsigned char*)(this+1);
120 unsigned char* trackData =trackDataStart;
121 unsigned char* trackDataEnd=trackDataStart+6400;
122
123 int lastSectorFound=0;
124 while (trackData<(trackDataEnd-16))
125 {
126 if ( (trackData[0]==0xa1) && (trackData[1]==0xa1) && (trackData[2]==0xa1) && (trackData[3]==0xfe) )
127 {
128 // Found a marker for a synchronization sequence for a sector [#A1 #A1 #A1], [#FE Track Side Sector tt CRC CRC]
129 int sectorNumber=trackData[6];
130 if (sectorNumber==(lastSectorFound+1))
131 {
132 lastSectorFound=sectorNumber;
133 }
134 else
135 {
136 ShowError("There's something wrong in the track structure of the floppy, the sector id does not make sense.");
137 }
138 trackData+=10; // Skip synchronization sequence
139 trackData+=34; // - gap2: 34 bytes (22xAE , 12x00)
140 trackData+=4; // - ?: 4 bytes (A1 A1 A1 FB)
141
142 if (sectorNumber==1)
143 {
144 firstSectorOffset=trackData-trackDataStart;
145 }
146 else
147 if (sectorNumber==2)
148 {
149 sectorInterleave=trackData-trackDataStart-firstSectorOffset;
150 }
151 trackData+=256; // Sector data
152 }
153 else
154 {
155 trackData++;
156 }
157 }
158
159 return lastSectorFound;
160 }
161
162
163
164 FileEntry::FileEntry() :
165 m_FloppyNumber(0),
166 m_StartSide(0),
167 m_StartTrack(0),
168 m_StartSector(1),
169 m_SectorCount(0),
170 m_LoadAddress(0),
171 m_FinalFileSize(0),
172 m_CompressionMode(e_CompressionNone),
173 m_StoredFileSize(0)
174 {
175 }
176
177 FileEntry::~FileEntry()
178 {
179 }
180
181
182
183
184 Floppy::Floppy() :
185 m_AllFilesAreResolved(true),
186 m_AllowMissingFiles(false),
187 m_Buffer(0),
188 m_BufferSize(0),
189 m_TrackNumber(0),
190 m_SectorNumber(0),
191 m_CurrentTrack(0),
192 m_CurrentSector(1),
193 m_LastFileWithMetadata(0),
194 m_CompressionMode(e_CompressionNone),
195 m_OffsetFirstSector(156), // 156 (Location of the first byte of data of the first sector)
196 m_InterSectorSpacing(358) // 358 (Number of bytes to skip to go to the next sector: 256+59+43)
197 {
198 }
199
200
201 Floppy::~Floppy()
202 {
203 delete m_Buffer;
204 }
205
206
207 unsigned int crctab[256] =
208 {
209 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
210 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
211 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
212 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
213 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
214 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
215 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
216 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
217 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
218 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
219 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
220 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
221 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
222 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
223 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
224 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
225 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
226 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
227 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
228 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
229 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
230 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
231 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
232 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
233 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
234 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
235 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
236 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
237 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
238 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
239 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
240 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
241 };
242
243 void compute_crc(unsigned char *ptr,int count)
244 {
245 int i;
246 unsigned short crc=0xFFFF,byte;
247 for (i=0;i<count;i++) {
248 byte= *ptr++;
249 crc=(crc<<8)^crctab[(crc>>8)^byte];
250 }
251 *ptr++=crc>>8;
252 *ptr++=crc&0xFF;
253 }
254
255
256 bool Floppy::CreateDisk(int numberOfSides,int numberOfTracks,int numberOfSectors)
257 {
258 // Heavily based on MakeDisk and Tap2DSk
259 int gap1,gap2,gap3;
260
261 switch (numberOfSectors)
262 {
263 case 15: case 16: case 17:
264 gap1=72; gap2=34; gap3=50;
265 break;
266
267 case 18:
268 gap1=12; gap2=34; gap3=46;
269 break;
270
271 default:
272 ShowError("Unrealistic sectors per track number\n");
273 }
274
275 m_BufferSize=256+numberOfSides*numberOfTracks*6400;
276 m_Buffer=malloc(m_BufferSize);
277 if (m_Buffer)
278 {
279 m_TrackNumber =numberOfTracks; // 42
280 m_SectorNumber=numberOfSectors; // 17
281 m_SideNumber =numberOfSides; // 2
282
283 FloppyHeader& header(*((FloppyHeader*)m_Buffer));
284 header.Clear();
285 header.SetSignature("MFM_DISK");
286 header.SetSideNumber(numberOfSides);
287 header.SetTrackNumber(numberOfTracks);
288 header.SetGeometry(1);
289
290 unsigned char* trackbuf=(unsigned char*)m_Buffer+256;
291 for (int s=0;s<numberOfSides;s++)
292 {
293 for (int t=0;t<numberOfTracks;t++)
294 {
295 {
296 int i;
297 int offset=0;
298 for (i=0;i<gap1-12;i++)
299 {
300 trackbuf[offset++]=0x4E;
301 }
302 for (int j=0;j<numberOfSectors;j++)
303 {
304 for (i=0;i<12;i++) trackbuf[offset++]=0;
305 for (i=0;i<3;i++) trackbuf[offset++]=0xA1;
306 trackbuf[offset++]=0xFE;
307 for (i=0;i<6;i++) offset++;
308 for (i=0;i<gap2-12;i++) trackbuf[offset++]=0x22;
309 for (i=0;i<12;i++) trackbuf[offset++]=0;
310 for (i=0;i<3;i++) trackbuf[offset++]=0xA1;
311 trackbuf[offset++]=0xFB;
312 for (i=0;i<258;i++) offset++;
313 for (i=0;i<gap3-12;i++) trackbuf[offset++]=0x4E;
314 }
315
316 while (offset<6400)
317 {
318 trackbuf[offset++]=0x4E;
319 }
320 }
321 int offset=gap1;
322 for (int i=0;i<numberOfSectors;i++)
323 {
324 trackbuf[offset+4]=t;
325 trackbuf[offset+5]=s;
326 trackbuf[offset+6]=i+1;
327 trackbuf[offset+7]=1;
328 compute_crc(trackbuf+offset,4+4);
329 offset+=4+6;
330 offset+=gap2;
331 memset(trackbuf+offset+4,0,256);
332 compute_crc(trackbuf+offset,4+256);
333 offset+=256+6;
334 offset+=gap3;
335 }
336 trackbuf+=6400;
337 }
338 }
339 if (header.IsValidHeader())
340 {
341 m_SectorNumber=header.FindNumberOfSectors(m_OffsetFirstSector,m_InterSectorSpacing); //17; // Can't figure out that from the header Oo
342 return true;
343 }
344 }
345
346 return false;
347 }
348
349
350 bool Floppy::LoadDisk(const char* fileName)
351 {
352 if (LoadFile(fileName,m_Buffer,m_BufferSize))
353 {
354 const FloppyHeader& header(*((FloppyHeader*)m_Buffer));
355 if (header.IsValidHeader())
356 {
357 m_TrackNumber =header.GetTrackNumber();
358 m_SideNumber =header.GetSideNumber();
359 m_SectorNumber=header.FindNumberOfSectors(m_OffsetFirstSector,m_InterSectorSpacing); //17; // Can't figure out that from the header Oo
360 return true;
361 }
362 }
363 return false;
364 }
365
366
367 bool Floppy::SaveDisk(const char* fileName) const
368 {
369 if (m_Buffer)
370 {
371 return SaveFile(fileName,m_Buffer,m_BufferSize);
372 }
373 return false;
374 }
375
376 /*
377 Début de la piste (facultatif): 80 [#4E], 12 [#00], [#C2 #C2 #C2 #FC] et 50 [#4E] (soit 146 octets selon
378 la norme IBM) ou 40 [#4E], 12 [#00], [#C2 #C2 #C2 #FC] et 40 [#4E] (soit 96 octets pour SEDORIC).
379
380 Pour chaque secteur: 12 [#00], 3 [#A1] [#FE #pp #ff #ss #tt CRC], 22 [#4E], 12 [#00], 3 [#A1], [#FB],
381 les 512 octets, [CRC CRC], 80 octets [#4E] (#tt = #02) (soit 141 + 512 = 653 octets selon la norme IBM)
382 ou 12 [#00], 3 [#A1] [#FE #pp #ff #ss #01 CRC CRC], 22 [#4E], 12 [#00], 3 [#A1], [#FB], les 256
383 octets, [CRC CRC], 12, 30 ou 40 octets [#4E] (selon le nombre de secteurs/piste). Soit environ 256 + (72
384 à 100) = 328 à 356 octets pour SEDORIC.
385
386 Fin de la piste (facultatif): un nombre variable d'octets [#4E
387
388 Selon NIBBLE,
389 une piste IBM compte 146 octets de début de piste + 9 secteurs de 653 octets + 257 octets de fin de piste = 6280 octets.
390 Une piste SEDORIC, formatée à 17 secteurs, compte 96 octets de début de piste + 17 secteurs de 358 octets + 98 octets de fin de piste = 6280 octets.
391 Une piste SEDORIC, formatée à 19 secteurs, compte 0 octet de début de piste + 19 secteurs de 328 octets + 48 octets de fin de piste = 6280 octets.
392 On comprend mieux le manque de fiabilité du formatage en 19 secteurs/piste dû à la faible largeur des zones de sécurité (12 [#4E] entre chaque secteur et 48 octets entre le dernier et le premier).
393
394 Lors de l'élaboration du tampon de formatage SEDORIC, les octets #C2 sont remplacés par des octets
395 #F6, les octets #A1 sont remplacés par des octets #F5 et chaque paire de 2 octets [CRC CRC] et
396 remplacée par un octet #F7. Comme on le voit, nombre de variantes sont utilisées, sauf la zone 22 [#4E],
397 12 [#00], 3 [#A1] qui est strictement obligatoire.
398
399 // From DskTool:
400 15, 16 or 17 sectors: gap1=72; gap2=34; gap3=50;
401 18 sectors: gap1=12; gap2=34; gap3=46;
402 */
403 // Header secteur
404 #define nb_oct_before_sector 59 // Cas de 17 secteurs/pistes !
405 #define nb_oct_after_sector 43 //#define nb_oct_after_sector 31
406
407 unsigned int Floppy::GetDskImageOffset()
408 {
409 unsigned int offset=256; // Add the DSK file header size
410 offset+=m_CurrentTrack*6400; // And move to the correct track
411 offset+=m_OffsetFirstSector; // Add the offset from the start of track to the data of the first sector
412 offset+=m_InterSectorSpacing*(m_CurrentSector-1);
413 return offset;
414 }
415
416
417 // 0x0319 -> 793
418 bool Floppy::WriteSector(const char *fileName)
419 {
420 if (!m_Buffer)
421 {
422 return false;
423 }
424
425 std::string filteredFileName(StringTrim(fileName," \t\f\v\n\r"));
426
427 void* buffer;
428 size_t bufferSize;
429
430 if (LoadFile(filteredFileName.c_str(),buffer,bufferSize))
431 {
432 if (bufferSize>256)
433 {
434 ShowError("File for sector is too large. %d bytes (%d too many)",bufferSize,bufferSize-256);
435 }
436
437 unsigned int sectorOffset=GetDskImageOffset();
438 if (m_BufferSize>sectorOffset+256)
439 {
440 memcpy((char*)m_Buffer+sectorOffset,buffer,bufferSize);
441 }
442 MarkCurrentSectorUsed();
443 printf("Boot sector '%s' installed, %d free bytes remaining in this sector.\n",filteredFileName.c_str(),256-bufferSize);
444
445 MoveToNextSector();
446 }
447 else
448 {
449 m_AllFilesAreResolved=false;
450 if (!m_AllowMissingFiles)
451 {
452 ShowError("Boot Sector file '%s' not found",filteredFileName.c_str());
453 }
454 }
455 return true;
456 }
457
458
459 class TapeInfo
460 {
461 public:
462 TapeInfo()
463 : m_StartAddress(0)
464 , m_EndAddress(0)
465 , m_FileType(0)
466 , m_AutoStarts(false)
467 , m_PtrData(nullptr)
468 , m_DataSize(0)
469 {
470
471 }
472
473 bool ParseHeader(void* fileBuffer,size_t fileSize)
474 {
475 m_DataSize=fileSize;
476 m_PtrData =(unsigned char*)fileBuffer;
477 while (m_DataSize && (m_PtrData[0]==0x16))
478 {
479 m_DataSize--;
480 m_PtrData++;
481 }
482 if (m_DataSize>8 && (m_PtrData[0]==0x24) /*&& (m_PtrData[1]==0x00) && (m_PtrData[2]==0x00)*/ ) // Harrier Attack has 0x24 0x80 0xBF
483 {
484 // At this point at least we have a valid synchro sequence and we know we have a usable header
485 m_FileType = m_PtrData[3];
486 m_AutoStarts =(m_PtrData[4]!=0);
487 m_EndAddress =(m_PtrData[5]<<8)|m_PtrData[6];
488 m_StartAddress=(m_PtrData[7]<<8)|m_PtrData[8];
489
490 m_DataSize-=9;
491 m_PtrData+=9;
492
493 if (m_DataSize /*&& (m_PtrData[0]==0x00)*/ ) // Harrier Attack has 0xE8
494 {
495 // Skip the zero
496 m_DataSize--;
497 m_PtrData++;
498
499 // Now we read the name
500 while (m_DataSize && (m_PtrData[0]!=0x00))
501 {
502 m_FileName+=m_PtrData[0];
503 m_DataSize--;
504 m_PtrData++;
505 }
506 if (m_DataSize && (m_PtrData[0]==0x00) )
507 {
508 // Skip the zero
509 m_DataSize--;
510 m_PtrData++;
511
512 // Now ptr points on the actual data
513 return true;
514 }
515 }
516 }
517 // Not a valid tape file
518 return false;
519 }
520
521 public:
522 unsigned char* m_PtrData;
523 int m_DataSize;
524 int m_StartAddress;
525 int m_EndAddress;
526 int m_FileType;
527 bool m_AutoStarts;
528 std::string m_FileName;
529 };
530
531
532 bool Floppy::WriteFile(const char *fileName,int loadAddress,bool removeHeaderIfPresent,const std::map<std::string,std::string>& metadata)
533 {
534 if (!m_Buffer)
535 {
536 return false;
537 }
538
539 void* fileBuffer;
540 size_t fileSize;
541 if (!LoadFile(fileName,fileBuffer,fileSize))
542 {
543 m_AllFilesAreResolved=false;
544 if (!m_AllowMissingFiles)
545 {
546 ShowError("Error can't open file '%s'\n",fileName);
547 }
548 const char* message="Place holder file generated by FloppyBuilder";
549 fileBuffer=strdup(message);
550 fileSize =strlen(message);
551 }
552
553 unsigned char* fileData=(unsigned char*)fileBuffer;
554
555 if (removeHeaderIfPresent)
556 {
557 TapeInfo tapeInfo;
558 if (!tapeInfo.ParseHeader(fileBuffer,fileSize))
559 {
560 ShowError("File '%s' is not a valid tape file\n",fileName);
561 }
562 // If the file was a valid tape header, then we use these new information
563 fileData=tapeInfo.m_PtrData;
564 fileSize=tapeInfo.m_DataSize;
565 loadAddress=tapeInfo.m_StartAddress;
566 }
567
568 FileEntry fileEntry;
569 fileEntry.m_FloppyNumber=0; // 0 for a single floppy program
570
571 if (m_CurrentTrack>41) // face 2
572 {
573 fileEntry.m_StartSide=1;
574 }
575 else
576 {
577 fileEntry.m_StartSide=0;
578 }
579
580 fileEntry.m_StartTrack =m_CurrentTrack; // 0 to 42 (80...)
581 fileEntry.m_StartSector=m_CurrentSector; // 1 to 17 (or 16 or 18...)
582 fileEntry.m_LoadAddress=loadAddress;
583 fileEntry.m_StoredFileSize=fileSize;
584 fileEntry.m_FinalFileSize =fileSize;
585 fileEntry.m_SectorCount=(fileSize+255)/256;
586 fileEntry.m_FilePath =fileName;
587 fileEntry.m_CompressionMode=e_CompressionNone;
588
589 if (!metadata.empty())
590 {
591 fileEntry.m_Metadata = metadata;
592 m_LastFileWithMetadata=m_FileEntries.size();
593 }
594
595 for (auto metadataIt(metadata.begin());metadataIt!=metadata.end();++metadataIt)
596 {
597 m_MetadataCategories.insert(metadataIt->first);
598 }
599
600 std::vector<unsigned char> compressedBuffer;
601 if (m_CompressionMode==e_CompressionFilepack)
602 {
603 // So the user requested FilePack compression.
604 // Great, we can do that.
605 compressedBuffer.resize(fileSize);
606 gLZ77_XorMask=0;
607 size_t compressedFileSize=LZ77_Compress(fileData,compressedBuffer.data(),fileSize);
608 if (compressedFileSize<fileSize)
609 {
610 // We actually did manage to compress the data
611 fileData=compressedBuffer.data();
612 fileSize=compressedFileSize;
613
614 fileEntry.m_CompressionMode=e_CompressionFilepack;
615 fileEntry.m_StoredFileSize=compressedFileSize;
616 fileEntry.m_SectorCount=(fileSize+255)/256;
617 }
618 }
619
620 //
621 // Finally write the data to the disk structure
622 //
623 while (fileSize)
624 {
625 unsigned int offset=SetPosition(m_CurrentTrack,m_CurrentSector);
626
627 int sizeToWrite=256;
628 if (fileSize<256)
629 {
630 sizeToWrite=fileSize;
631 }
632 fileSize-=sizeToWrite;
633
634 MarkCurrentSectorUsed();
635 memset((char*)m_Buffer+offset,0,256);
636 memcpy((char*)m_Buffer+offset,fileData,sizeToWrite);
637 fileData+=sizeToWrite;
638
639 if (!MoveToNextSector())
640 {
641 ShowError("Floppy disk is full, not enough space to store '%s'.\n",fileName);
642 }
643 }
644 free(fileBuffer);
645
646 m_FileEntries.push_back(fileEntry);
647
648 return true;
649 }
650
651
652 bool Floppy::ExtractFile(const char *fileName,int trackNumber,int sectorNumber,int sectorCount)
653 {
654 if (!m_Buffer)
655 {
656 return false;
657 }
658
659 int memoTrack=m_CurrentTrack;
660 int memoSector=m_CurrentSector;
661
662 if (trackNumber>=128)
663 {
664 trackNumber=(trackNumber-128)+m_TrackNumber;
665 }
666
667 SetPosition(trackNumber,sectorNumber);
668
669 std::vector<char> fileBuffer;
670 fileBuffer.resize(sectorCount*256);
671
672 char* writeAddress=fileBuffer.data();
673 while (sectorCount--)
674 {
675 unsigned int offset=SetPosition(m_CurrentTrack,m_CurrentSector);
676 memcpy(writeAddress,(char*)m_Buffer+offset,256);
677 writeAddress+=256;
678
679 if (!MoveToNextSector())
680 {
681 ShowError("Reach the end of disk when extracting '%s'.\n",fileName);
682 }
683 }
684 if (!SaveFile(fileName,fileBuffer.data(),fileBuffer.size()))
685 {
686 ShowError("Reach the end of disk when extracting '%s'.\n",fileName);
687 }
688
689
690 // Restore the old position
691 SetPosition(memoTrack,memoSector);
692 return true;
693 }
694
695
696 void Floppy::MarkCurrentSectorUsed()
697 {
698 int magicValue=(m_SectorNumber*m_CurrentTrack)+m_CurrentSector;
699 if (m_SectorUsageMap.find(magicValue)!=m_SectorUsageMap.end())
700 {
701 ShowError("Sector %d was already allocated",magicValue);
702 }
703 m_SectorUsageMap.insert(magicValue);
704 }
705
706 bool Floppy::SaveDescription(const char* fileName) const
707 {
708 std::stringstream layoutInfo;
709 layoutInfo << "//\n";
710 layoutInfo << "// Floppy layout generated by FloppyBuilder " << TOOL_VERSION_MAJOR << "." << TOOL_VERSION_MINOR << "\n";
711 if (!m_AllFilesAreResolved)
712 {
713 layoutInfo << "// (The generated floppy is missing some files, a new build pass is required)\n";
714 }
715 layoutInfo << "//\n";
716 layoutInfo << "\n";
717
718 layoutInfo << "#ifdef ASSEMBLER\n";
719 layoutInfo << "//\n";
720 layoutInfo << "// Information for the Assembler\n";
721 layoutInfo << "//\n";
722 layoutInfo << "#ifdef LOADER\n";
723
724 std::stringstream code_sector;
725 std::stringstream code_track;
726 std::stringstream code_compressed;
727 std::stringstream code_size_low;
728 std::stringstream code_size_high;
729 std::stringstream code_stored_size_low;
730 std::stringstream code_stored_size_high;
731 std::stringstream code_adress_low;
732 std::stringstream code_adress_high;
733
734 std::map<std::string,std::stringstream> metadata_content;
735
736 std::set<std::string> metadata_entries;
737
738 {
739 for (auto metadataIt(m_MetadataCategories.begin());metadataIt!=m_MetadataCategories.end();metadataIt++)
740 {
741 const std::string& metadataCategoryName(*metadataIt);
742 metadata_content[metadataCategoryName+"_Low"] << "_MetaData_" << metadataCategoryName << "_Low .byt ";
743 metadata_content[metadataCategoryName+"_High"] << "_MetaData_" << metadataCategoryName << "_High .byt ";
744 }
745 }
746
747
748 std::stringstream file_list_summary;
749
750 int counter=0;
751 for (auto it(m_FileEntries.begin());it!=m_FileEntries.end();++it)
752 {
753 const FileEntry& fileEntry(*it);
754
755 if (it!=m_FileEntries.begin())
756 {
757 code_adress_low << ",";
758 code_adress_high << ",";
759
760 code_stored_size_low << ",";
761 code_stored_size_high << ",";
762
763 code_size_low << ",";
764 code_size_high << ",";
765
766 code_sector << ",";
767 code_track << ",";
768
769 code_compressed << ",";
770
771 if (counter<=m_LastFileWithMetadata)
772 {
773 for (auto metadataIt(metadata_content.begin());metadataIt!=metadata_content.end();metadataIt++)
774 {
775 metadataIt->second << ",";
776 }
777 }
778 }
779 code_adress_low << "<" << fileEntry.m_LoadAddress;
780 code_adress_high << ">" << fileEntry.m_LoadAddress;
781
782 code_size_low << "<" << fileEntry.m_FinalFileSize;
783 code_size_high << ">" << fileEntry.m_FinalFileSize;
784
785 code_stored_size_low << "<" << fileEntry.m_StoredFileSize;
786 code_stored_size_high << ">" << fileEntry.m_StoredFileSize;
787
788 code_sector << fileEntry.m_StartSector;
789
790 file_list_summary << "// Entry #" << counter << " '"<< fileEntry.m_FilePath << "'\n";
791 file_list_summary << "// - Loads at address " << fileEntry.m_LoadAddress;
792 if (fileEntry.m_StartTrack<m_TrackNumber)
793 {
794 // First side
795 file_list_summary << " starts on track " << fileEntry.m_StartTrack;
796 code_track << fileEntry.m_StartTrack;
797 }
798 else
799 {
800 // Second side
801 file_list_summary << " starts on the second side on track " << (fileEntry.m_StartTrack-m_TrackNumber);
802 code_track << fileEntry.m_StartTrack-m_TrackNumber+128;
803 }
804 file_list_summary << " sector " << fileEntry.m_StartSector << " and is " << fileEntry.m_SectorCount << " sectors long ";
805
806 if (fileEntry.m_CompressionMode==e_CompressionNone)
807 {
808 // Uncompressed file
809 file_list_summary << "(" << fileEntry.m_FinalFileSize << " bytes).\n";
810 }
811 else
812 {
813 // Compressed file
814 file_list_summary << "(" << fileEntry.m_StoredFileSize << " compressed bytes: " << (fileEntry.m_StoredFileSize*100)/fileEntry.m_FinalFileSize << "% of " << fileEntry.m_FinalFileSize << " bytes).\n";
815 }
816
817 if (counter<=m_LastFileWithMetadata)
818 {
819 if (!fileEntry.m_Metadata.empty())
820 {
821 file_list_summary << "// - Associated metadata: ";
822 }
823 for (auto metadataIt(m_MetadataCategories.begin());metadataIt!=m_MetadataCategories.end();metadataIt++)
824 {
825 const std::string& metadataCategoryName(*metadataIt);
826
827 std::string metadataLabelEntry;
828 std::string metadataEntry;
829
830 auto fileMetadataIt=fileEntry.m_Metadata.find(metadataCategoryName);
831 if (fileMetadataIt==fileEntry.m_Metadata.end())
832 {
833 // No entries for that one
834 metadataLabelEntry="metadata_none";
835 metadataEntry=metadataLabelEntry+" .byt \"\",0";
836 }
837 else
838 {
839 const std::string& key(fileMetadataIt->first);
840 const std::string& value(fileMetadataIt->second);
841 file_list_summary << key << "='" << value << "' ";
842
843 std::string labelValue(StringMakeLabel(value));
844 metadataLabelEntry="metadata_"+key+"_"+labelValue;
845 metadataEntry=metadataLabelEntry+" .byt \""+value+"\",0";
846 }
847 metadata_entries.insert(metadataEntry);
848 metadata_content[metadataCategoryName+"_Low"] << "<" << metadataLabelEntry;
849 metadata_content[metadataCategoryName+"_High"] << ">" << metadataLabelEntry;
850 }
851 if (!fileEntry.m_Metadata.empty())
852 {
853 file_list_summary << "\n";
854 }
855 }
856
857 /*
858 if (!fileEntry.m_Metadata.empty())
859 {
860 for (auto metaIt(fileEntry.m_Metadata.begin());metaIt!=fileEntry.m_Metadata.end();++metaIt)
861 {
862 }
863 }
864 file_list_summary << "\n";
865 */
866
867 ++counter;
868 }
869
870
871 layoutInfo << "FileStartSector .byt ";
872 layoutInfo << code_sector.str() << "\n";
873
874 layoutInfo << "FileStartTrack .byt ";
875 layoutInfo << code_track.str() << "\n";
876
877 layoutInfo << "FileStoredSizeLow .byt ";
878 layoutInfo << code_stored_size_low.str() << "\n";
879
880 layoutInfo << "FileStoredSizeHigh .byt ";
881 layoutInfo << code_stored_size_high.str() << "\n";
882
883 layoutInfo << "FileSizeLow .byt ";
884 layoutInfo << code_size_low.str() << "\n";
885
886 layoutInfo << "FileSizeHigh .byt ";
887 layoutInfo << code_size_high.str() << "\n";
888
889 layoutInfo << "FileLoadAdressLow .byt ";
890 layoutInfo << code_adress_low.str() << "\n";
891
892 layoutInfo << "FileLoadAdressHigh .byt ";
893 layoutInfo << code_adress_high.str() << "\n";
894
895
896 layoutInfo << "#endif // LOADER\n";
897
898 layoutInfo << "#else\n";
899 layoutInfo << "//\n";
900 layoutInfo << "// Information for the Compiler\n";
901 layoutInfo << "//\n";
902 layoutInfo << "#endif\n";
903
904 layoutInfo << "\n";
905 layoutInfo << "//\n";
906 layoutInfo << "// Summary for this floppy building session:\n";
907 layoutInfo << "//\n";
908 layoutInfo << "#define FLOPPY_SIDE_NUMBER " << m_SideNumber << " // Number of sides\n";
909 layoutInfo << "#define FLOPPY_TRACK_NUMBER " << m_TrackNumber << " // Number of tracks\n";
910 layoutInfo << "#define FLOPPY_SECTOR_PER_TRACK " << m_SectorNumber << " // Number of sectors per track\n";
911
912 layoutInfo << "\n";
913 layoutInfo << "//\n";
914 layoutInfo << "// List of files written to the floppy\n";
915 layoutInfo << "//\n";
916 layoutInfo << file_list_summary.str();
917 layoutInfo << "//\n";
918
919 int totalAvailableSectors=m_TrackNumber*m_SectorNumber*m_SideNumber;
920 layoutInfo << "// " << m_SectorUsageMap.size() << " sectors used, out of " << totalAvailableSectors << ". (" << (m_SectorUsageMap.size()*100)/totalAvailableSectors << "% of the total disk size used)\n";
921 layoutInfo << "//\n";
922
923 if (m_DefineList.empty())
924 {
925 layoutInfo << "// No defines set\n";
926 }
927 else
928 {
929 for (auto it(m_DefineList.begin());it!=m_DefineList.end();++it)
930 {
931 layoutInfo << "#define " << it->first << " " << it->second << "\n";
932 ++counter;
933 }
934 }
935
936 layoutInfo << "\n";
937 layoutInfo << "//\n";
938 layoutInfo << "// Metadata\n";
939 layoutInfo << "//\n";
940 layoutInfo << "#ifdef METADATA_STORAGE\n";
941
942 {
943 for (auto metadataIt(metadata_entries.begin());metadataIt!=metadata_entries.end();metadataIt++)
944 {
945 layoutInfo << *metadataIt << "\n";
946 }
947 }
948 layoutInfo << "\n";
949
950 {
951 for (auto metadataIt(metadata_content.begin());metadataIt!=metadata_content.end();metadataIt++)
952 {
953 layoutInfo << metadataIt->second.str() << "\n";
954 }
955 }
956 layoutInfo << "#endif // METADATA_STORAGE\n";
957 layoutInfo << "\n";
958
959 if (!SaveFile(fileName,layoutInfo.str().c_str(),layoutInfo.str().length()))
960 {
961 ShowError("Can't save '%s'\n",fileName);
962 }
963
964 return true;
965 }
966
967
968 bool Floppy::AddDefine(std::string defineName,std::string defineValue)
969 {
970 // Ugly token replacement, can do more optimal but as long as it works...
971 {
972 std::stringstream tempValue;
973 tempValue << m_FileEntries.size();
974 StringReplace(defineName ,"{FileIndex}",tempValue.str());
975 StringReplace(defineValue,"{FileIndex}",tempValue.str());
976 }
977
978 m_DefineList.push_back(std::pair<std::string,std::string>(defineName,defineValue));
979 return true;
980 }

  ViewVC Help
Powered by ViewVC 1.1.26