/[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 1095 - (show annotations)
Wed Jan 29 13:46:25 2014 UTC (5 years, 10 months ago) by dbug
File size: 28174 byte(s)
FloppyBuilder 0.14
- The MetaData tables will now not contain any information after the last file that declared metadata, this allows to not waste room in the loader for dummy data

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) )
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) )
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 void Floppy::MarkCurrentSectorUsed()
652 {
653 int magicValue=(m_SectorNumber*m_CurrentTrack)+m_CurrentSector;
654 if (m_SectorUsageMap.find(magicValue)!=m_SectorUsageMap.end())
655 {
656 ShowError("Sector %d was already allocated",magicValue);
657 }
658 m_SectorUsageMap.insert(magicValue);
659 }
660
661 bool Floppy::SaveDescription(const char* fileName) const
662 {
663 std::stringstream layoutInfo;
664 layoutInfo << "//\n";
665 layoutInfo << "// Floppy layout generated by FloppyBuilder " << TOOL_VERSION_MAJOR << "." << TOOL_VERSION_MINOR << "\n";
666 if (!m_AllFilesAreResolved)
667 {
668 layoutInfo << "// (The generated floppy is missing some files, a new build pass is required)\n";
669 }
670 layoutInfo << "//\n";
671 layoutInfo << "\n";
672
673 layoutInfo << "#ifdef ASSEMBLER\n";
674 layoutInfo << "//\n";
675 layoutInfo << "// Information for the Assembler\n";
676 layoutInfo << "//\n";
677 layoutInfo << "#ifdef LOADER\n";
678
679 std::stringstream code_sector;
680 std::stringstream code_track;
681 std::stringstream code_compressed;
682 std::stringstream code_size_low;
683 std::stringstream code_size_high;
684 std::stringstream code_stored_size_low;
685 std::stringstream code_stored_size_high;
686 std::stringstream code_adress_low;
687 std::stringstream code_adress_high;
688
689 std::map<std::string,std::stringstream> metadata_content;
690
691 std::set<std::string> metadata_entries;
692
693 {
694 for (auto metadataIt(m_MetadataCategories.begin());metadataIt!=m_MetadataCategories.end();metadataIt++)
695 {
696 const std::string& metadataCategoryName(*metadataIt);
697 metadata_content[metadataCategoryName+"_Low"] << "_MetaData_" << metadataCategoryName << "_Low .byt ";
698 metadata_content[metadataCategoryName+"_High"] << "_MetaData_" << metadataCategoryName << "_High .byt ";
699 }
700 }
701
702
703 std::stringstream file_list_summary;
704
705 int counter=0;
706 for (auto it(m_FileEntries.begin());it!=m_FileEntries.end();++it)
707 {
708 const FileEntry& fileEntry(*it);
709
710 if (it!=m_FileEntries.begin())
711 {
712 code_adress_low << ",";
713 code_adress_high << ",";
714
715 code_stored_size_low << ",";
716 code_stored_size_high << ",";
717
718 code_size_low << ",";
719 code_size_high << ",";
720
721 code_sector << ",";
722 code_track << ",";
723
724 code_compressed << ",";
725
726 if (counter<=m_LastFileWithMetadata)
727 {
728 for (auto metadataIt(metadata_content.begin());metadataIt!=metadata_content.end();metadataIt++)
729 {
730 metadataIt->second << ",";
731 }
732 }
733 }
734 code_adress_low << "<" << fileEntry.m_LoadAddress;
735 code_adress_high << ">" << fileEntry.m_LoadAddress;
736
737 code_size_low << "<" << fileEntry.m_FinalFileSize;
738 code_size_high << ">" << fileEntry.m_FinalFileSize;
739
740 code_stored_size_low << "<" << fileEntry.m_StoredFileSize;
741 code_stored_size_high << ">" << fileEntry.m_StoredFileSize;
742
743 code_sector << fileEntry.m_StartSector;
744
745 file_list_summary << "// Entry #" << counter << " '"<< fileEntry.m_FilePath << "'\n";
746 file_list_summary << "// - Loads at address " << fileEntry.m_LoadAddress;
747 if (fileEntry.m_StartTrack<m_TrackNumber)
748 {
749 // First side
750 file_list_summary << " starts on track " << fileEntry.m_StartTrack;
751 code_track << fileEntry.m_StartTrack;
752 }
753 else
754 {
755 // Second side
756 file_list_summary << " starts on the second side on track " << (fileEntry.m_StartTrack-m_TrackNumber);
757 code_track << fileEntry.m_StartTrack-m_TrackNumber+128;
758 }
759 file_list_summary << " sector " << fileEntry.m_StartSector << " and is " << fileEntry.m_SectorCount << " sectors long ";
760
761 if (fileEntry.m_CompressionMode==e_CompressionNone)
762 {
763 // Uncompressed file
764 file_list_summary << "(" << fileEntry.m_FinalFileSize << " bytes).\n";
765 }
766 else
767 {
768 // Compressed file
769 file_list_summary << "(" << fileEntry.m_StoredFileSize << " compressed bytes: " << (fileEntry.m_StoredFileSize*100)/fileEntry.m_FinalFileSize << "% of " << fileEntry.m_FinalFileSize << " bytes).\n";
770 }
771
772 if (counter<=m_LastFileWithMetadata)
773 {
774 if (!fileEntry.m_Metadata.empty())
775 {
776 file_list_summary << "// - Associated metadata: ";
777 }
778 for (auto metadataIt(m_MetadataCategories.begin());metadataIt!=m_MetadataCategories.end();metadataIt++)
779 {
780 const std::string& metadataCategoryName(*metadataIt);
781
782 std::string metadataLabelEntry;
783 std::string metadataEntry;
784
785 auto fileMetadataIt=fileEntry.m_Metadata.find(metadataCategoryName);
786 if (fileMetadataIt==fileEntry.m_Metadata.end())
787 {
788 // No entries for that one
789 metadataLabelEntry="metadata_none";
790 metadataEntry=metadataLabelEntry+" .byt \"\",0";
791 }
792 else
793 {
794 const std::string& key(fileMetadataIt->first);
795 const std::string& value(fileMetadataIt->second);
796 file_list_summary << key << "='" << value << "' ";
797
798 std::string labelValue(StringMakeLabel(value));
799 metadataLabelEntry="metadata_"+key+"_"+labelValue;
800 metadataEntry=metadataLabelEntry+" .byt \""+value+"\",0";
801 }
802 metadata_entries.insert(metadataEntry);
803 metadata_content[metadataCategoryName+"_Low"] << "<" << metadataLabelEntry;
804 metadata_content[metadataCategoryName+"_High"] << ">" << metadataLabelEntry;
805 }
806 if (!fileEntry.m_Metadata.empty())
807 {
808 file_list_summary << "\n";
809 }
810 }
811
812 /*
813 if (!fileEntry.m_Metadata.empty())
814 {
815 for (auto metaIt(fileEntry.m_Metadata.begin());metaIt!=fileEntry.m_Metadata.end();++metaIt)
816 {
817 }
818 }
819 file_list_summary << "\n";
820 */
821
822 ++counter;
823 }
824
825
826 layoutInfo << "FileStartSector .byt ";
827 layoutInfo << code_sector.str() << "\n";
828
829 layoutInfo << "FileStartTrack .byt ";
830 layoutInfo << code_track.str() << "\n";
831
832 layoutInfo << "FileStoredSizeLow .byt ";
833 layoutInfo << code_stored_size_low.str() << "\n";
834
835 layoutInfo << "FileStoredSizeHigh .byt ";
836 layoutInfo << code_stored_size_high.str() << "\n";
837
838 layoutInfo << "FileSizeLow .byt ";
839 layoutInfo << code_size_low.str() << "\n";
840
841 layoutInfo << "FileSizeHigh .byt ";
842 layoutInfo << code_size_high.str() << "\n";
843
844 layoutInfo << "FileLoadAdressLow .byt ";
845 layoutInfo << code_adress_low.str() << "\n";
846
847 layoutInfo << "FileLoadAdressHigh .byt ";
848 layoutInfo << code_adress_high.str() << "\n";
849
850
851 layoutInfo << "#endif // LOADER\n";
852
853 layoutInfo << "#else\n";
854 layoutInfo << "//\n";
855 layoutInfo << "// Information for the Compiler\n";
856 layoutInfo << "//\n";
857 layoutInfo << "#endif\n";
858
859 layoutInfo << "\n";
860 layoutInfo << "//\n";
861 layoutInfo << "// Summary for this floppy building session:\n";
862 layoutInfo << "//\n";
863 layoutInfo << "#define FLOPPY_SIDE_NUMBER " << m_SideNumber << " // Number of sides\n";
864 layoutInfo << "#define FLOPPY_TRACK_NUMBER " << m_TrackNumber << " // Number of tracks\n";
865 layoutInfo << "#define FLOPPY_SECTOR_PER_TRACK " << m_SectorNumber << " // Number of sectors per track\n";
866
867 layoutInfo << "\n";
868 layoutInfo << "//\n";
869 layoutInfo << "// List of files written to the floppy\n";
870 layoutInfo << "//\n";
871 layoutInfo << file_list_summary.str();
872 layoutInfo << "//\n";
873
874 int totalAvailableSpace=m_TrackNumber*m_SectorNumber*m_SideNumber;
875 layoutInfo << "// " << m_SectorUsageMap.size() << " sectors used, out of " << totalAvailableSpace << ". (" << (m_SectorUsageMap.size()*100)/totalAvailableSpace << "% of the total available size used)\n";
876 layoutInfo << "//\n";
877
878 if (m_DefineList.empty())
879 {
880 layoutInfo << "// No defines set\n";
881 }
882 else
883 {
884 for (auto it(m_DefineList.begin());it!=m_DefineList.end();++it)
885 {
886 layoutInfo << "#define " << it->first << " " << it->second << "\n";
887 ++counter;
888 }
889 }
890
891 layoutInfo << "\n";
892 layoutInfo << "//\n";
893 layoutInfo << "// Metadata\n";
894 layoutInfo << "//\n";
895 layoutInfo << "#ifdef METADATA_STORAGE\n";
896
897 {
898 for (auto metadataIt(metadata_entries.begin());metadataIt!=metadata_entries.end();metadataIt++)
899 {
900 layoutInfo << *metadataIt << "\n";
901 }
902 }
903 layoutInfo << "\n";
904
905 {
906 for (auto metadataIt(metadata_content.begin());metadataIt!=metadata_content.end();metadataIt++)
907 {
908 layoutInfo << metadataIt->second.str() << "\n";
909 }
910 }
911 layoutInfo << "#endif // METADATA_STORAGE\n";
912 layoutInfo << "\n";
913
914 if (!SaveFile(fileName,layoutInfo.str().c_str(),layoutInfo.str().length()))
915 {
916 ShowError("Can't save '%s'\n",fileName);
917 }
918
919 return true;
920 }
921
922
923 bool Floppy::AddDefine(std::string defineName,std::string defineValue)
924 {
925 // Ugly token replacement, can do more optimal but as long as it works...
926 {
927 std::stringstream tempValue;
928 tempValue << m_FileEntries.size();
929 StringReplace(defineName ,"{FileIndex}",tempValue.str());
930 StringReplace(defineValue,"{FileIndex}",tempValue.str());
931 }
932
933 m_DefineList.push_back(std::pair<std::string,std::string>(defineName,defineValue));
934 return true;
935 }

  ViewVC Help
Powered by ViewVC 1.1.26