Subversion Repositories pentevo

Rev

Rev 798 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
796 DimkaM 1
#include "std.h"
2
 
3
#include "emul.h"
4
#include "vars.h"
5
#include "fdd.h"
6
#include "util.h"
7
 
8
// ��� ������ ������ ipf ����� � ������� big endian
9
 
10
static constexpr size_t CAPS_MAXPLATFORM = 4;
11
 
12
static constexpr char ID_CAPS[] = "CAPS";
13
static constexpr char ID_INFO[] = "INFO";
14
static constexpr char ID_IMGE[] = "IMGE";
15
static constexpr char ID_DATA[] = "DATA";
16
 
17
static constexpr u16 MFM_MARK_A1 = 0x4489;
18
static constexpr u16 MFM_MARK_C2 = 0x5224;
19
 
20
static inline u32 be2cpu(u32 x)
21
{
22
    return _byteswap_ulong(x);
23
}
24
 
25
static inline u16 be2cpu(u16 x)
26
{
27
    return _byteswap_ushort(x);
28
}
29
 
30
static inline u8 ReadU8(u8 *&Ptr)
31
{
32
    u8 x = *Ptr++;
33
    return x;
34
}
35
 
36
static inline u16 ReadU16(u8 *&Ptr)
37
{
38
    u16 x = *((u16 *)Ptr);
39
    Ptr += sizeof(u16);
40
    return x;
41
}
42
 
43
static inline u32 ReadU32(u8 *&Ptr)
44
{
45
    u32 x = *((u32 *)Ptr);
46
    Ptr += sizeof(u32);
47
    return x;
48
}
49
 
50
#pragma pack(push, 1)
51
struct TCapsId
52
{
53
    char Name[4];
54
    u32 Size;
55
    u32 Crc;
56
};
57
 
58
enum TEncoderType : u32
59
{
60
    CAPS_ENCODER = 1,
61
    SPS_ENCODER = 2
62
};
63
 
64
// caps packed date.time format
65
struct TCapsDateTime
66
{
67
    u32 date; // packed date, yyyymmdd
68
    u32 time; // packed time, hhmmssttt
69
};
70
 
71
// platform IDs, not about configuration, but intended use
72
enum TPlatformId : u32
73
{
74
    cppidNA = 0, // invalid platform (dummy entry)
75
    cppidAmiga,
76
    cppidAtariST,
77
    cppidPC,
78
    cppidAmstradCPC,
79
    cppidSpectrum,
80
    cppidSamCoupe,
81
    cppidArchimedes,
82
    cppidC64,
83
    cppidAtari8,
84
    cppidLast
85
};
86
 
87
 
88
// image information
89
struct TCapsInfo
90
{
91
    u32 type;        // image type
92
    TEncoderType encoder;     // image encoder ID
93
    u32 encrev;      // image encoder revision
94
    u32 release;     // release ID
95
    u32 revision;    // release revision ID
96
    u32 origin;      // original source reference
97
    u32 mincylinder; // lowest cylinder number
98
    u32 maxcylinder; // highest cylinder number
99
    u32 minhead;     // lowest head number
100
    u32 maxhead;     // highest head number
101
    TCapsDateTime crdt;  // image creation date.time
102
    TPlatformId platform[CAPS_MAXPLATFORM]; // intended platform(s)
103
    u32 disknum;     // disk# for release, >= 1 if multidisk
104
    u32 userid;      // user id of the image creator
105
    u32 reserved[3]; // future use
106
};
107
 
108
// density types
109
enum TDensityType : u32
110
{
111
    cpdenNA = 0,     // invalid density
112
    cpdenNoise,    // cells are unformatted (random size)
113
    cpdenAuto,     // automatic cell size, according to track size
114
    cpdenCLAmiga,  // Copylock Amiga
115
    cpdenCLAmiga2, // Copylock Amiga, new
116
    cpdenCLST,     // Copylock ST
117
    cpdenSLAmiga,  // Speedlock Amiga
118
    cpdenSLAmiga2, // Speedlock Amiga, old
119
    cpdenABAmiga,  // Adam Brierley Amiga
120
    cpdenABAmiga2, // Adam Brierley, density key Amiga
121
    cpdenLast
122
};
123
 
124
// signal processing used
125
enum TSigType : u32
126
{
127
    cpsigNA = 0, // invalid signal type
128
    cpsig2us,  // 2us cells
129
    cpsigLast
130
};
131
 
132
 
133
// track image descriptor
134
struct TCapsImage
135
{
136
    u32 cylinder; // cylinder#
137
    u32 head;     // head#
138
    TDensityType dentype;  // density type
139
    TSigType sigtype;  // signal processing type
140
    u32 trksize;  // decoded track size, rounded
141
    u32 startpos; // start position, rounded
142
    u32 startbit; // start position on original data
143
    u32 databits; // decoded data size in bits
144
    u32 gapbits;  // decoded gap size in bits
145
    u32 trkbits;  // decoded track size in bits
146
    u32 blkcnt;   // number of blocks
147
    u32 process;  // encoder prcocess
148
    u32 flag;     // image flags
149
    u32 did;      // data chunk identifier
150
    u32 reserved[3]; // future use
151
};
152
 
153
// data area
154
struct TCapsData
155
{
156
    u32 size;  // data area size in bytes after chunk
157
    u32 bsize; // data area size in bits
158
    u32 dcrc;  // data area crc
159
    u32 did;   // data chunk identifier
160
};
161
 
162
// original meaning of some CapsBlock entries for old images
163
struct TCapsBlockExt
164
{
165
    u32 blocksize;  // decoded block size, rounded
166
    u32 gapsize;    // decoded gap size, rounded
167
};
168
 
169
// new meaning of some CapsBlock entries for new images
170
struct TSPSBlockExt
171
{
172
    u32 gapoffset;  // offset of gap stream in data area
173
    u32 celltype;   // bitcell type
174
};
175
 
176
// union for old or new images
177
union TCapsBlockType
178
{
179
    TCapsBlockExt caps; // access old image
180
    TSPSBlockExt sps;   // access new image
800 DimkaM 181
    static_assert(sizeof(sps) == sizeof(caps),"static_assert");
796 DimkaM 182
};
183
 
184
// encoder types
185
enum TEncType : u32
186
{
187
    cpencNA = 0, // invalid encoder
188
    cpencMFM,  // MFM
189
    cpencRaw,  // no encoder used, test data only
190
    cpencLast
191
};
192
 
193
// CapsBlock flags
194
union TCapsBlockFlags // ������� ������� ����� � ��������� ������������� little endian
195
{
196
    struct
197
    {
198
        u32 CAPS_BF_GP0 : 1; // bit0
199
        u32 CAPS_BF_GP1 : 1; // bit1
200
        u32 CAPS_BF_DMB : 1; // bit2
201
        u32 : 29;
202
    };
203
    u32 Flags;
204
};
205
 
206
// block image descriptor
207
struct TCapsBlock
208
{
209
    u32 blockbits;  // decoded block size in bits
210
    u32 gapbits;    // decoded gap size in bits
211
    TCapsBlockType bt;  // content depending on image type
212
    TEncType enctype;    // encoder type
213
    TCapsBlockFlags flag;       // block flags
214
    u32 gapvalue;   // default gap value
215
    u32 dataoffset; // offset of data stream in data area (������������ ������� caps �����)
216
};
217
 
218
// gap types
219
enum TGapType : u8
220
{
221
    cpgapEnd = 0, // gap stream end
222
    cpgapCount, // gap counter
223
    cpgapData,  // gap data pattern
224
    cpgapLast
225
};
226
 
227
union TGapStreamElementHdr
228
{
229
    struct
230
    {
231
        TGapType GapType : 5;
232
        u8 GapSizeWidth : 3;
233
    };
234
    u8 Hdr;
235
};
236
 
237
// data types
238
enum TDataType : u8
239
{
240
    cpdatEnd = 0, // data stream end
241
    cpdatMark,  // mark/sync
242
    cpdatData,  // data
243
    cpdatGap,   // gap
244
    cpdatRaw,   // raw
245
    cpdatFData, // flakey data
246
    cpdatLast
247
};
248
 
249
union TDataStreamElementHdr
250
{
251
    struct
252
    {
253
        TDataType DataType : 5;
254
        u8 DataSizeWidth : 3;
255
    };
256
    u8 Hdr;
257
};
258
#pragma pack(pop)
259
 
260
static void ReadCapsId(TCapsId *CapsId, u8 *&Ptr)
261
{
262
    memcpy(CapsId->Name, Ptr, 4); Ptr += 4;
263
    CapsId->Size = be2cpu(ReadU32(Ptr));
264
    CapsId->Crc = be2cpu(ReadU32(Ptr));
265
}
266
 
267
static void ReadCapsDateTime(TCapsDateTime *CapsDateTime, u8 *&Ptr)
268
{
269
    CapsDateTime->date = be2cpu(ReadU32(Ptr));
270
    CapsDateTime->time = be2cpu(ReadU32(Ptr));
271
}
272
 
273
static void ReadCapsInfo(TCapsInfo *CapsInfo, u8 *&Ptr)
274
{
275
    CapsInfo->type = be2cpu(ReadU32(Ptr));
276
    CapsInfo->encoder = TEncoderType(be2cpu(ReadU32(Ptr)));
277
    CapsInfo->encrev = be2cpu(ReadU32(Ptr));
278
    CapsInfo->release = be2cpu(ReadU32(Ptr));
279
    CapsInfo->revision = be2cpu(ReadU32(Ptr));
280
    CapsInfo->origin = be2cpu(ReadU32(Ptr));
281
    CapsInfo->mincylinder = be2cpu(ReadU32(Ptr));
282
    CapsInfo->maxcylinder = be2cpu(ReadU32(Ptr));
283
    CapsInfo->minhead = be2cpu(ReadU32(Ptr));
284
    CapsInfo->maxhead = be2cpu(ReadU32(Ptr));
285
    ReadCapsDateTime(&CapsInfo->crdt, Ptr);
286
    for(auto &v : CapsInfo->platform)
287
    {
288
        v = TPlatformId(be2cpu(ReadU32(Ptr)));
289
    }
290
    CapsInfo->disknum = be2cpu(ReadU32(Ptr));
291
    CapsInfo->userid = be2cpu(ReadU32(Ptr));
292
 
293
    for(auto &v : CapsInfo->reserved)
294
    {
295
        v = be2cpu(ReadU32(Ptr));
296
    }
297
}
298
 
299
static void ReadCapsImage(TCapsImage *CapsImage, u8 *&Ptr)
300
{
301
    CapsImage->cylinder = be2cpu(ReadU32(Ptr));
302
    CapsImage->head = be2cpu(ReadU32(Ptr));
303
    CapsImage->dentype = TDensityType(be2cpu(ReadU32(Ptr)));
304
    CapsImage->sigtype = TSigType(be2cpu(ReadU32(Ptr)));
305
    CapsImage->trksize = be2cpu(ReadU32(Ptr));
306
    CapsImage->startpos = be2cpu(ReadU32(Ptr));
307
    CapsImage->startbit = be2cpu(ReadU32(Ptr));
308
    CapsImage->databits = be2cpu(ReadU32(Ptr));
309
    CapsImage->gapbits = be2cpu(ReadU32(Ptr));
310
    CapsImage->trkbits = be2cpu(ReadU32(Ptr));
311
    CapsImage->blkcnt = be2cpu(ReadU32(Ptr));
312
    CapsImage->process = be2cpu(ReadU32(Ptr));
313
    CapsImage->flag = be2cpu(ReadU32(Ptr));
314
    CapsImage->did = be2cpu(ReadU32(Ptr));
315
    for(auto &v : CapsImage->reserved)
316
    {
317
        v = be2cpu(ReadU32(Ptr));
318
    }
319
}
320
 
321
static void ReadCapsData(TCapsData *CapsData, u8 *&Ptr)
322
{
323
    CapsData->size = be2cpu(ReadU32(Ptr));
324
    CapsData->bsize = be2cpu(ReadU32(Ptr));
325
    CapsData->dcrc = be2cpu(ReadU32(Ptr));
326
    CapsData->did = be2cpu(ReadU32(Ptr));
327
}
328
 
329
static void ReadCapsBlockType(TCapsBlockType *CapsBlockType, TEncoderType EncoderType, u8 *&Ptr)
330
{
331
    switch(EncoderType)
332
    {
333
    case CAPS_ENCODER:
334
        CapsBlockType->caps.blocksize = be2cpu(ReadU32(Ptr));
335
        CapsBlockType->caps.gapsize = be2cpu(ReadU32(Ptr));
336
        break;
337
    case SPS_ENCODER:
338
        CapsBlockType->sps.gapoffset = be2cpu(ReadU32(Ptr));
339
        CapsBlockType->sps.celltype = be2cpu(ReadU32(Ptr));
340
        break;
341
    default:
342
        assert(!"unknown encoder type");
343
    }
344
}
345
 
346
static void ReadCapsBlock(TCapsBlock *CapsBlock, TEncoderType EncoderType, u8 *&Ptr)
347
{
348
    CapsBlock->blockbits = be2cpu(ReadU32(Ptr));
349
    CapsBlock->gapbits = be2cpu(ReadU32(Ptr));
350
    ReadCapsBlockType(&CapsBlock->bt, EncoderType, Ptr);
351
    CapsBlock->enctype = TEncType(be2cpu(ReadU32(Ptr)));
352
    CapsBlock->flag.Flags = be2cpu(ReadU32(Ptr));
353
    CapsBlock->gapvalue = be2cpu(ReadU32(Ptr));
354
    CapsBlock->dataoffset = be2cpu(ReadU32(Ptr));
355
}
356
 
357
static void ReadGapHdr(TGapStreamElementHdr *GapStreamElementHdr, u8 *&Ptr)
358
{
359
    GapStreamElementHdr->Hdr = *Ptr++;
360
}
361
 
362
static u32 ReadVarUint(unsigned n, u8 *&Ptr)
363
{
364
    u32 v = 0;
365
    for(unsigned i = 0; i < n; i++)
366
    {
367
        v |= unsigned(*Ptr) << (n - i - 1) * 8;
368
        Ptr++;
369
    }
370
 
371
    return v;
372
}
373
 
374
static void ReadDataHdr(TDataStreamElementHdr *DataStreamElementHdr, u8 *&Ptr)
375
{
376
    DataStreamElementHdr->Hdr = *Ptr++;
377
}
378
 
379
int FDD::read_ipf()
380
{
381
    u8 *Gptr = snbuf;
382
 
383
    u8 *Ptr = Gptr;
384
    TCapsId CapsId;
385
    ReadCapsId(&CapsId, Ptr);
386
 
387
    Gptr += CapsId.Size;
388
    Ptr = Gptr;
389
 
390
    if(memcmp(CapsId.Name, ID_CAPS, sizeof(CapsId.Name)) != 0)
391
    {
392
        return 0;
393
    }
394
 
395
    ReadCapsId(&CapsId, Ptr);
396
    if(memcmp(CapsId.Name, ID_INFO, sizeof(CapsId.Name)) != 0)
397
    {
398
        return 0;
399
    }
400
 
401
    TCapsInfo CapsInfo;
402
    ReadCapsInfo(&CapsInfo, Ptr);
403
 
404
    Gptr += CapsId.Size;
405
    Ptr = Gptr;
406
    u8 *ImgeStart = Gptr; // ������ ������� ������� IMGE
407
 
408
    if(CapsInfo.maxcylinder >= MAX_CYLS)
409
    {
410
        err_printf("cylinders (%u) > MAX_CYLS(%d)", cyls, MAX_CYLS);
411
        return 0;
412
    }
413
 
414
    if(CapsInfo.maxhead >= 2)
415
    {
416
        err_printf("sides (%u) > 2", sides);
417
        return 0;
418
    }
419
 
420
    cyls = CapsInfo.maxcylinder + 1;
421
    sides = CapsInfo.maxhead + 1;
422
 
423
    size_t mem = 0;
424
    const unsigned bitmap_len = (unsigned(MAX_TRACK_LEN + 7U)) >> 3;
425
 
426
    mem += (MAX_CYLS - cyls) * sides * (MAX_TRACK_LEN + bitmap_len); // ������� ��� ����������� �������������� �� MAX_CYLS �������
427
 
428
    rawsize = align_by(mem, 4096U);
429
    rawdata = (unsigned char*)VirtualAlloc(nullptr, rawsize, MEM_COMMIT, PAGE_READWRITE);
430
    u8 *dst = rawdata;
431
 
432
    auto Ncyls{ CapsInfo.maxcylinder - CapsInfo.mincylinder + 1 };
433
    auto Nheads{ CapsInfo.maxhead - CapsInfo.minhead + 1 };
434
 
435
    u8 *DataStart2 = Gptr + (Ncyls * Nheads)*(sizeof(TCapsId) + sizeof(TCapsImage));
436
 
437
    // �������������� ����� � ������ �����
438
    for(unsigned c = 0; c < CapsInfo.mincylinder; c++)
439
    {
440
        for(unsigned h = 0; h < sides; h++)
441
        {
442
            trklen[c][h] = MAX_TRACK_LEN;
443
            trkd[c][h] = dst;
444
            dst += MAX_TRACK_LEN;
445
 
446
            trki[c][h] = dst;
447
            dst += bitmap_len;
448
        }
449
    }
450
 
451
    for(unsigned c = CapsInfo.mincylinder; c <= CapsInfo.maxcylinder; c++)
452
    {
453
        for(unsigned h = CapsInfo.minhead; h <= CapsInfo.maxhead; h++)
454
        {
455
            ReadCapsId(&CapsId, Ptr);
456
            assert(memcmp(CapsId.Name, ID_IMGE, sizeof(CapsId.Name)) == 0);
457
 
458
            TCapsImage CapsImage;
459
            ReadCapsImage(&CapsImage, Ptr);
460
            assert(CapsImage.cylinder == c && CapsImage.head == h);
461
 
462
            Gptr += CapsId.Size;
463
            Ptr = Gptr;
464
        }
465
    }
466
 
467
    u8 *DataStart = Gptr; // ������ ������� ������� DATA
468
    assert(DataStart == DataStart2);
469
 
470
    for(unsigned c = CapsInfo.mincylinder; c <= CapsInfo.maxcylinder; c++)
471
    {
472
        for(unsigned h = CapsInfo.minhead; h <= CapsInfo.maxhead; h++)
473
        {
474
            ReadCapsId(&CapsId, Ptr);
475
            assert(memcmp(CapsId.Name, ID_DATA, sizeof(CapsId.Name)) == 0);
476
 
477
            TCapsData CapsData; // ����� ���������� �����
478
            ReadCapsData(&CapsData, Ptr);
479
 
480
            u8 *PtrCapsBlock = Ptr;
481
            Gptr += CapsId.Size + CapsData.size;
482
 
483
            Ptr = ImgeStart + (sizeof(TCapsId) + sizeof(TCapsImage)) * (CapsData.did - 1);
484
 
485
            ReadCapsId(&CapsId, Ptr);
486
            assert(memcmp(CapsId.Name, ID_IMGE, sizeof(CapsId.Name)) == 0);
487
 
488
            TCapsImage CapsImage;
489
            ReadCapsImage(&CapsImage, Ptr);
490
            assert(CapsImage.cylinder == c && CapsImage.head == h);
491
            assert(CapsImage.did == CapsData.did);
492
 
493
//            assert(CapsImage.trksize % 2 == 0);
494
            unsigned sz = min(unsigned(CapsImage.trksize / 2), unsigned(MAX_TRACK_LEN)); // ������ � ������� ������� / 8
495
            trklen[c][h] = sz;
496
            trkd[c][h] = dst;
497
 
498
            u8 *dsti = dst + sz;
499
            trki[c][h] = dsti;
500
 
501
            Ptr = PtrCapsBlock;
502
 
503
            u32 FixedGapSize = 0;
504
 
505
            // ������ ���������� ������� ���� ������������� GAP'��
506
            for(unsigned i = 0; i < CapsImage.blkcnt; i++)
507
            {
508
                TCapsBlock CapsBlock;
509
                ReadCapsBlock(&CapsBlock, CapsInfo.encoder, Ptr);
510
                u8 *Optr = Ptr;
511
 
512
                Ptr = PtrCapsBlock + CapsBlock.bt.sps.gapoffset;
513
 
514
                auto GalcGapSize = [&Ptr, &FixedGapSize]()
515
                {
516
                    bool IsEnd = false;
517
                    u32 Count = 0;
518
                    do
519
                    {
520
                        TGapStreamElementHdr GapHdr;
521
                        ReadGapHdr(&GapHdr, Ptr);
522
 
523
                        IsEnd = (GapHdr.GapSizeWidth == 0 && GapHdr.GapType == cpgapEnd);
524
                        if(GapHdr.GapSizeWidth != 0)
525
                        {
526
                            u32 Size = ReadVarUint(GapHdr.GapSizeWidth, Ptr); // �������� � �����
527
                            Size = (Size + 7) / 8; // �������� � ������
528
                            switch(GapHdr.GapType)
529
                            {
530
                            case cpgapCount:
531
                                Count = Size;
532
                                break;
533
                            case cpgapData:
534
                            {
535
                                FixedGapSize += Count * Size;
536
 
537
                                Ptr += Size;
538
                                break;
539
                            }
540
                            }
541
                        }
542
                    } while(!IsEnd);
543
                };
544
 
545
                if(CapsBlock.flag.CAPS_BF_GP0) // Fw gap
546
                {
547
                    GalcGapSize();
548
                }
549
 
550
                if(CapsBlock.flag.CAPS_BF_GP1) // Bw gap
551
                {
552
                    GalcGapSize();
553
                }
554
 
555
                Ptr = Optr;
556
            }
557
 
558
 
559
            // ������� � ������� ������� / 8, ��������� � ����������� ����� �����
560
            // (������ ipf ����� ����� ����� ����� > 100000 ������� �����)
561
            // ������ ������ ������� �� ��������� � ���������� ��������� �������� ��������
562
            // (��������� �� +3 �� ����� ��������� ������������ �������� ��������, � ���������� ��������� � ��������,
563
            // � �� ���������� ������������� ��������� � ������ ��������)
564
            // http://www.cpcwiki.eu/index.php/Amstrad_FDD_part (�� +3 ����������� ����������� ���������)
565
            u32 RealGapBits = MAX_TRACK_LEN * 16 - CapsImage.databits;
566
            assert(RealGapBits >= FixedGapSize * 16);
567
            u32 AvailGapBits = RealGapBits - FixedGapSize * 16;
568
            u32 FlexGapBits = CapsImage.gapbits - FixedGapSize * 16;
569
            u32 StartPos = (FlexGapBits != 0) ? (CapsImage.startbit * AvailGapBits) / (16 * FlexGapBits) : 0;
570
            if(StartPos < 13)
571
            {
572
                StartPos = 13; // 4E + 12(00)
573
            }
574
 
575
            dst += StartPos;
576
 
577
            Ptr = PtrCapsBlock;
578
 
579
            for(unsigned i = 0; i < CapsImage.blkcnt; i++)
580
            {
581
                TCapsBlock CapsBlock;
582
                ReadCapsBlock(&CapsBlock, CapsInfo.encoder, Ptr);
583
                u8 *Optr = Ptr;
584
 
585
                unsigned GapBitsRemaining = CapsBlock.gapbits / 2; // ��� �� ����, � MFM ������ (�� � 2 ���� ������ ��� �����)
586
 
587
                assert(CapsInfo.encoder == SPS_ENCODER);
588
 
589
 
590
                Ptr = PtrCapsBlock + CapsBlock.dataoffset;
591
 
592
                bool IsEnd = false;
593
                do
594
                {
595
                    TDataStreamElementHdr DataHdr;
596
                    ReadDataHdr(&DataHdr, Ptr);
597
 
598
                    IsEnd = (DataHdr.DataSizeWidth == 0 && DataHdr.DataType == cpdatEnd);
599
                    if(DataHdr.DataSizeWidth != 0)
600
                    {
601
                        u32 Size = ReadVarUint(DataHdr.DataSizeWidth, Ptr);
602
                        if(CapsBlock.flag.CAPS_BF_DMB) // ������ ������ � �����
603
                        {
604
//                            assert(Size % 8 == 0);
605
                            Size = (Size + 7) / 8;
606
                        }
607
                        switch(DataHdr.DataType)
608
                        {
609
                        case cpdatMark: // ����������� �������������� �� �������� MFM
610
                        {
611
                            u8 *Optr2 = Ptr;
612
                            assert(Size % 2 == 0);
613
                            for(unsigned j = 0; j < Size / 2; j++)
614
                            {
615
                                u16 Mark = be2cpu(ReadU16(Ptr));
616
                                assert(dst + 1 - trkd[c][h] <= trklen[c][h]);
617
                                unsigned pos = unsigned(dst - trkd[c][h]);
618
                                switch(Mark)
619
                                {
620
                                case MFM_MARK_A1: // A1
621
                                    *dst++ = 0xA1;
622
                                    set_i(c, h, pos);
623
                                    break;
624
                                case MFM_MARK_C2: // C2
625
                                    *dst++ = 0xC2;
626
                                    set_i(c, h, pos);
627
                                    break;
628
                                default:
629
                                    assert(!"unknown mark");
630
                                }
631
                            }
632
                            Ptr = Optr2;
633
                            break;
634
                        }
635
                        case cpdatData: // ������ (� ���� ������������� ������)
636
                        case cpdatGap: // ����������� gap (� ���� ������������� ������)
637
                            assert(dst + Size - trkd[c][h] <= trklen[c][h]);
638
                            memcpy(dst, Ptr, Size);
639
                            dst += Size;
640
                            break;
641
                        default:
642
                            assert(!"invalid data type");
643
                        }
644
                        Ptr += Size;
645
                    }
646
                } while(!IsEnd);
647
 
648
                Ptr = PtrCapsBlock + CapsBlock.bt.sps.gapoffset;
649
 
650
                auto ProcessGap = [&Ptr, &dst, &GapBitsRemaining, StartPos, c, h, i, this]()
651
                {
652
                    bool IsEnd = false;
653
                    u32 Count = 0;
654
                    u8 *GapPtr = nullptr;
655
                    u32 GapDataSize = 0;
656
                    do
657
                    {
658
                        TGapStreamElementHdr GapHdr;
659
                        ReadGapHdr(&GapHdr, Ptr);
660
 
661
                        IsEnd = (GapHdr.GapSizeWidth == 0 && GapHdr.GapType == cpgapEnd);
662
                        if(GapHdr.GapSizeWidth != 0)
663
                        {
664
                            u32 Size = ReadVarUint(GapHdr.GapSizeWidth, Ptr); // �������� � �����
665
                            Size = (Size + 7) / 8; // �������� � ������
666
                            switch(GapHdr.GapType)
667
                            {
668
                            case cpgapCount:
669
                                Count = Size;
670
                                break;
671
                            case cpgapData:
672
                            {
673
//                                printf("c=%u,h=%u,i=%u,o=0x%X\n", c, h, i, unsigned(dst - trkd[c][h] + 0x13));
674
 
675
                                if(Count == 0) // GAP ���������� �����
676
                                {
677
                                    if(dst - trkd[c][h] >= trklen[c][h]) // ������ �����
678
                                    {
679
                                        GapPtr = Ptr;
680
                                        GapDataSize = Size;
681
                                    }
682
                                    else // ����� �����
683
                                    {
684
                                        Count = min(GapBitsRemaining / 8, unsigned(trklen[c][h] - (dst - trkd[c][h])));
685
                                    }
686
                                }
687
 
688
                                if(dst - trkd[c][h] < trklen[c][h])
689
                                {
690
                                    while(Count)
691
                                    {
692
                                        assert(dst - trkd[c][h] < trklen[c][h]);
693
                                        memcpy(dst, Ptr, Size);
694
                                        dst += Size;
695
                                        GapBitsRemaining -= Size * 8;
696
                                        Count--;
697
                                    }
698
                                }
699
                                else if(Count != 0)
700
                                {
701
                                    assert(StartPos >= Count * Size);
702
                                    dst = trkd[c][h] + StartPos - Count * Size;
703
 
704
                                    u32 CountOld = Count;
705
                                    while(Count) // GAP ������������� ����� ����� C2C2C2FC
706
                                    {
707
                                        assert(dst - trkd[c][h] < trklen[c][h]);
708
                                        memcpy(dst, Ptr, Size);
709
                                        dst += Size;
710
                                        GapBitsRemaining -= Size * 8;
711
                                        Count--;
712
                                    }
713
 
714
                                    if(GapPtr) // GAP ���������� ����� � ������ �����
715
                                    {
716
                                        dst = trkd[c][h];
717
                                        Count = StartPos - CountOld * Size;
718
 
719
                                        while(Count)
720
                                        {
721
                                            assert(dst - trkd[c][h] < trklen[c][h]);
722
                                            memcpy(dst, GapPtr, GapDataSize);
723
                                            dst += GapDataSize;
724
                                            GapBitsRemaining -= GapDataSize * 8;
725
                                            Count--;
726
                                        }
727
 
728
                                        GapPtr = nullptr;
729
                                    }
730
                                }
731
                                Ptr += Size;
732
                                break;
733
                            }
734
                            }
735
                        }
736
                    } while(!IsEnd);
737
                };
738
 
739
                if(CapsBlock.flag.CAPS_BF_GP0) // Fw gap
740
                {
741
                    ProcessGap();
742
                }
743
 
744
                if(CapsBlock.flag.CAPS_BF_GP1) // Bw gap
745
                {
746
                    ProcessGap();
747
                }
748
 
749
//                assert(GapBitsRemaining == 0);
750
                Ptr = Optr;
751
            }
752
 
753
            dst += sz - (dst - trkd[c][h]);
754
            assert(dst - trkd[c][h] == sz);
755
            dst += (unsigned(sz + 7)) >> 3;
756
            Ptr = Gptr;
757
        }
758
    }
759
 
760
    // �������������� ����� � ����� �����
761
    for(unsigned c = CapsInfo.maxcylinder + 1; c < MAX_CYLS; c++)
762
    {
763
        for(unsigned h = 0; h < sides; h++)
764
        {
765
            trklen[c][h] = MAX_TRACK_LEN;
766
            trkd[c][h] = dst;
767
            dst += MAX_TRACK_LEN;
768
 
769
            trki[c][h] = dst;
770
            dst += bitmap_len;
771
        }
772
    }
773
 
774
    return 1;
775
}