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

  ViewVC Help
Powered by ViewVC 1.1.26