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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1072 - (show annotations)
Wed Jan 8 21:07:43 2014 UTC (5 years, 10 months ago) by dbug
File size: 27834 byte(s)
FloppyBuilder 0.13
- Added a new parameter to make it possible to bootstrap the floppy building process: With 'init' a description fill be generated even if data is missing,
this makes it possible to do a multi-pass build process which will not fail because it depends on things not yet generated :)

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

  ViewVC Help
Powered by ViewVC 1.1.26