KiCad PCB EDA Suite
Loading...
Searching...
No Matches
allegro_parser.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright Quilter
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22
23#include <array>
24#include <cstring>
25
26#include <wx/sstream.h>
27#include <wx/log.h>
28#include <wx/translation.h>
29
30#include <core/profile.h>
31#include <core/throttle.h>
32#include <core/type_helpers.h>
33#include <ki_exception.h>
34
35using namespace ALLEGRO;
36
37
45static const wxChar* const traceAllegroParser = wxT( "KICAD_ALLEGRO_PARSER" );
46static const wxChar* const traceAllegroParserBlocks = wxT( "KICAD_ALLEGRO_PARSER_BLOCKS" );
47static const wxChar* const traceAllegroPerf = wxT( "KICAD_ALLEGRO_PERF" );
48
49
51{
52 uint32_t w1 = aStream.ReadU32();
53 uint32_t w2 = aStream.ReadU32();
54
55 if( aVer >= FMT_VER::V_180 )
56 {
57 // V18 stores head (chain start key) first, tail (sentinel key) second
59 .m_Tail = w2,
60 .m_Head = w1,
61 };
62 }
63
64 // V16/V17 stores tail (sentinel pointer) first, head (chain start) second
66 .m_Tail = w1,
67 .m_Head = w2,
68 };
69}
70
71
72static double ReadAllegroFloat( FILE_STREAM& aStream )
73{
74 const uint32_t a = aStream.ReadU32();
75 const uint32_t b = aStream.ReadU32();
76
77 // Combine into a 64-bit integer
78 const uint64_t combined = ( static_cast<uint64_t>( a ) << 32 ) + b;
79
80 // Copy the bits into a double
81 double result = 0;
82 std::memcpy( &result, &combined, sizeof( result ) );
83 return result;
84}
85
86
87template <typename ARRAY>
88static void ReadArrayU32( FILE_STREAM& aStream, ARRAY& aArray )
89{
90 for( size_t i = 0; i < aArray.size(); i++ )
91 {
92 aArray[i] = aStream.ReadU32();
93 }
94}
95
96
97template <typename T>
98static T ReadField( FILE_STREAM& aStream, FMT_VER aFmtVer )
99{
100 T field;
101 if constexpr( std::is_same_v<T, uint32_t> )
102 {
103 field = aStream.ReadU32();
104 }
105 else if constexpr( std::is_same_v<T, uint8_t> )
106 {
107 field = aStream.ReadU8();
108 }
109 else if constexpr( std::is_same_v<T, uint16_t> )
110 {
111 field = aStream.ReadU16();
112 }
113 else if constexpr( std::is_same_v<T, int16_t> )
114 {
115 field = aStream.ReadS16();
116 }
117 else if constexpr( std::is_same_v<T, int32_t> )
118 {
119 field = aStream.ReadS32();
120 }
121 else if constexpr( std::is_same_v<T, FILE_HEADER::LINKED_LIST> )
122 {
123 field = ReadLL( aStream, aFmtVer );
124 }
125 else if constexpr( requires { std::tuple_size<T>::value; } )
126 {
127 for( size_t i = 0; i < std::tuple_size_v<T>; ++i )
128 field[i] = aStream.ReadU32();
129 }
130 else
131 {
132 static_assert( always_false<T>::value, "Unsupported type for ReadField" );
133 }
134
135 return field;
136}
137
138
143template <typename COND_T>
144static void ReadCond( FILE_STREAM& aStream, FMT_VER aFmtVer, COND_T& aField )
145{
146 if( COND_T::exists( aFmtVer ) )
147 {
148 aField = ReadField<typename COND_T::value_type>( aStream, aFmtVer );
149 }
150}
151
152
154{
155 uint32_t masked = aMagic & 0xFFFFFF00;
156
157 switch( masked )
158 {
159 case 0x00130000: return FMT_VER::V_160;
160 case 0x00130200: return FMT_VER::V_161;
161 case 0x00130400:
162 case 0x00130500: return FMT_VER::V_162;
163 case 0x00130C00: return FMT_VER::V_164;
164 case 0x00131000: return FMT_VER::V_165;
165 case 0x00131500: return FMT_VER::V_166;
166 case 0x00140400:
167 case 0x00140500:
168 case 0x00140600:
169 case 0x00140700: return FMT_VER::V_172;
170 case 0x00140900:
171 case 0x00140E00: return FMT_VER::V_174;
172 case 0x00141500: return FMT_VER::V_175;
173 case 0x00150000: return FMT_VER::V_180;
174 case 0x00150200: return FMT_VER::V_181;
175 case 0x00160100: return FMT_VER::V_190;
176 default: break;
177 }
178
179 // Pre-v16 Allegro files use a fundamentally different binary format
180 // that cannot be parsed by this importer. The header is still compatible enough to read
181 // the Allegro version string for a helpful error message.
182 uint32_t majorVer = ( aMagic >> 16 ) & 0xFFFF;
183
184 if( majorVer <= 0x0012 )
185 return FMT_VER::V_PRE_V16;
186
187 // Allegro 14 and 15 keep the family in the top byte of the magic
188 const uint32_t topByte = aMagic >> 24;
189
190 if( topByte >= 0x0F && topByte <= 0x12 && ( aMagic & 0x00FF0000 ) == 0 )
191 return FMT_VER::V_PRE_V16;
192
193 // Struct sizes depend on version, so we can't do anything useful with
194 // unrecognized formats. Report the magic and ask the user to report it.
195 THROW_IO_ERRORF( _( "Unknown Allegro file version %#010x (rev %d)" ), aMagic, majorVer - 3 );
196}
197
198
199std::unique_ptr<ALLEGRO::FILE_HEADER> HEADER_PARSER::ParseHeader()
200{
201 auto header = std::make_unique<ALLEGRO::FILE_HEADER>();
202 const size_t headerStartPos = m_stream.Position();
203
204 uint32_t fileMagic = m_stream.ReadU32();
205 m_fmtVer = FormatFromMagic( fileMagic );
206
207 header->m_Magic = fileMagic;
208
209 header->m_Unknown1a = m_stream.ReadU32();
210 header->m_FileRole = m_stream.ReadU32();
211 header->m_Unknown1b = m_stream.ReadU32();
212 header->m_WriterProgram = m_stream.ReadU32();
213
214 header->m_ObjectCount = m_stream.ReadU32();
215
216 header->m_UnknownMagic = m_stream.ReadU32();
217 header->m_UnknownFlags = m_stream.ReadU32();
218
219 ReadCond( m_stream, m_fmtVer, header->m_Unknown2_preV18 );
220
221 ReadCond( m_stream, m_fmtVer, header->m_Unknown2a_V18 );
222 ReadCond( m_stream, m_fmtVer, header->m_Unknown2b_V18 );
223 ReadCond( m_stream, m_fmtVer, header->m_0x27_End_V18 );
224 ReadCond( m_stream, m_fmtVer, header->m_Unknown2d_V18 );
225 ReadCond( m_stream, m_fmtVer, header->m_Unknown2e_V18 );
226 ReadCond( m_stream, m_fmtVer, header->m_StringCount_V18 );
227 ReadCond( m_stream, m_fmtVer, header->m_Unknown2g_V18 );
228
229 ReadCond( m_stream, m_fmtVer, header->m_LL_V18_1 );
230 ReadCond( m_stream, m_fmtVer, header->m_LL_V18_2 );
231 ReadCond( m_stream, m_fmtVer, header->m_LL_V18_3 );
232 ReadCond( m_stream, m_fmtVer, header->m_LL_V18_4 );
233 ReadCond( m_stream, m_fmtVer, header->m_LL_V18_5 );
234
235 // V18 positions 5-22 match v16 positions 0-17
236 header->m_LL_0x04 = ReadLL( m_stream, m_fmtVer );
237 header->m_LL_0x06 = ReadLL( m_stream, m_fmtVer );
238 header->m_LL_0x0C = ReadLL( m_stream, m_fmtVer );
239 header->m_LL_Shapes = ReadLL( m_stream, m_fmtVer );
240 header->m_LL_0x14 = ReadLL( m_stream, m_fmtVer );
241 header->m_LL_0x1B_Nets = ReadLL( m_stream, m_fmtVer );
242 header->m_LL_0x1C = ReadLL( m_stream, m_fmtVer );
243 header->m_LL_0x24_0x28 = ReadLL( m_stream, m_fmtVer );
244 header->m_LL_Unknown1 = ReadLL( m_stream, m_fmtVer );
245 header->m_LL_0x2B = ReadLL( m_stream, m_fmtVer );
246 header->m_LL_0x03_0x30 = ReadLL( m_stream, m_fmtVer );
247 header->m_LL_0x0A = ReadLL( m_stream, m_fmtVer );
248 header->m_LL_0x1D_0x1E_0x1F = ReadLL( m_stream, m_fmtVer );
249 header->m_LL_Unknown2 = ReadLL( m_stream, m_fmtVer );
250 header->m_LL_0x38 = ReadLL( m_stream, m_fmtVer );
251 header->m_LL_0x2C = ReadLL( m_stream, m_fmtVer );
252 header->m_LL_0x0C_2 = ReadLL( m_stream, m_fmtVer );
253 header->m_LL_Unknown3 = ReadLL( m_stream, m_fmtVer );
254
255 ReadCond( m_stream, m_fmtVer, header->m_0x35_Start_preV18 );
256 ReadCond( m_stream, m_fmtVer, header->m_0x35_End_preV18 );
257
258 ReadCond( m_stream, m_fmtVer, header->m_LL_Unknown5_V18 );
259 header->m_LL_0x36 = ReadLL( m_stream, m_fmtVer );
260 ReadCond( m_stream, m_fmtVer, header->m_LL_Unknown5_preV18 );
261
262 header->m_LL_Unknown6 = ReadLL( m_stream, m_fmtVer );
263 header->m_LL_0x0A_2 = ReadLL( m_stream, m_fmtVer );
264
265 ReadCond( m_stream, m_fmtVer, header->m_Unknown3 );
266
267 ReadCond( m_stream, m_fmtVer, header->m_LL_V18_6 );
268 ReadCond( m_stream, m_fmtVer, header->m_0x35_Start_V18 );
269 ReadCond( m_stream, m_fmtVer, header->m_Unknown_V181 );
270 ReadCond( m_stream, m_fmtVer, header->m_0x35_End_V18 );
271
272 // Quick check that the positions line up
273 // (start of the m_AllegroVersion string is easy to find)
275 wxASSERT( m_stream.Position() - headerStartPos == 0xF8 );
276 else if( m_fmtVer < FMT_VER::V_181 )
277 wxASSERT( m_stream.Position() - headerStartPos == 0x124 );
278 else
279 wxASSERT( m_stream.Position() - headerStartPos == 0x144 );
280
281 m_stream.ReadBytes( header->m_AllegroVersion.data(), header->m_AllegroVersion.size() );
282 header->m_Unknown4 = m_stream.ReadU32();
283 header->m_MaxKey = m_stream.ReadU32();
284
285 ReadCond( m_stream, m_fmtVer, header->m_Unknown5_preV18 );
286 ReadCond( m_stream, m_fmtVer, header->m_Unknown5_V18 );
287
288 {
289 uint8_t units = m_stream.ReadU8();
290
291 switch( units )
292 {
298 header->m_BoardUnits = static_cast<BOARD_UNITS>( units );
299 break;
300
301 default:
302 THROW_IO_ERRORF( _( "Unknown board units %d" ), units );
303 }
304
305 m_stream.Skip( 3 );
306 }
307
308 header->m_Unknown6 = m_stream.ReadU32();
309
310 ReadCond( m_stream, m_fmtVer, header->m_Unknown7 );
311 ReadCond( m_stream, m_fmtVer, header->m_0x27_End_preV18 );
312
313 header->m_Unknown8 = m_stream.ReadU32();
314
315 ReadCond( m_stream, m_fmtVer, header->m_StringCount_preV18 );
316
317 ReadArrayU32( m_stream, header->m_Unknown9 );
318
319 header->m_Unknown10a = m_stream.ReadU32();
320 header->m_Unknown10b = m_stream.ReadU32();
321 header->m_Unknown10c = m_stream.ReadU32();
322
323 header->m_UnitsDivisor = m_stream.ReadU32();
324
325 m_stream.SkipU32( m_fmtVer >= FMT_VER::V_181 ? 102 : 110 );
326
327 for( size_t i = 0; i < header->m_LayerMap.size(); ++i )
328 {
329 header->m_LayerMap[i].m_A = m_stream.ReadU32();
330 header->m_LayerMap[i].m_LayerList0x2A = m_stream.ReadU32();
331 }
332
333 wxLogTrace( traceAllegroParser, wxT( "Parsed header: %d objects, %d strings" ), header->m_ObjectCount,
334 header->GetStringsCount() );
335
336 return header;
337}
338
339
340static void ReadStringMap( FILE_STREAM& stream, BRD_DB& aDb, uint32_t count )
341{
342 // Fixed file offset of the string table in Allegro board files.
343 // As far as known, this is always a fixed value.
344 static constexpr size_t STRING_TABLE_OFFSET = 0x1200;
345
346 stream.Seek( STRING_TABLE_OFFSET );
347
348 for( uint32_t i = 0; i < count; ++i )
349 {
350 uint32_t id = stream.ReadU32();
351 wxString str = stream.ReadString( true );
352
353 aDb.AddString( id, std::move( str ) );
354 }
355}
356
357
359{
360 uint8_t classCode = aStream.ReadU8();
361 uint8_t subclassCode = aStream.ReadU8();
362
363 // Don't try to be clever and assign enums here - there are loads of them,
364 // and we don't have a perfect map yet.
365 return LAYER_INFO{
366 .m_Class = classCode,
367 .m_Subclass = subclassCode,
368 };
369}
370
371
372static std::unique_ptr<BLOCK_BASE> ParseBlock_0x01_ARC( FILE_STREAM& aStream, FMT_VER aVer )
373{
374 auto block = std::make_unique<BLOCK<BLK_0x01_ARC>>( aStream.Position() );
375
376 auto& data = block->GetData();
377
378 aStream.Skip( 1 );
379
380 data.m_UnknownByte = aStream.ReadU8();
381 data.m_SubType = aStream.ReadU8();
382 data.m_Key = aStream.ReadU32();
383 block->SetKey( data.m_Key );
384 data.m_Next = aStream.ReadU32();
385 block->SetNext( data.m_Next );
386 data.m_Parent = aStream.ReadU32();
387 data.m_Unknown1 = aStream.ReadU32();
388
389 ReadCond( aStream, aVer, data.m_Unknown6 );
390
391 data.m_Width = aStream.ReadU32();
392
393 data.m_StartX = aStream.ReadS32();
394 data.m_StartY = aStream.ReadS32();
395 data.m_EndX = aStream.ReadS32();
396 data.m_EndY = aStream.ReadS32();
397
398 data.m_CenterX = ReadAllegroFloat( aStream );
399 data.m_CenterY = ReadAllegroFloat( aStream );
400 data.m_Radius = ReadAllegroFloat( aStream );
401
402 for( size_t i = 0; i < data.m_BoundingBoxCoords.size(); ++i )
403 {
404 data.m_BoundingBoxCoords[i] = aStream.ReadS32();
405 }
406
407 return block;
408}
409
410
411static std::unique_ptr<BLOCK_BASE> ParseBlock_0x03( FILE_STREAM& aStream, FMT_VER aVer )
412{
413 auto block = std::make_unique<BLOCK<BLK_0x03_FIELD>>( aStream.Position() );
414
415 auto& data = block->GetData();
416
417 aStream.Skip( 1 );
418
419 data.m_Hdr1 = aStream.ReadU16();
420 data.m_Key = aStream.ReadU32();
421 block->SetKey( data.m_Key );
422 data.m_Next = aStream.ReadU32();
423 block->SetNext( data.m_Next );
424
425 ReadCond( aStream, aVer, data.m_Unknown1 );
426
427 data.m_SubType = aStream.ReadU8();
428 data.m_Hdr2 = aStream.ReadU8();
429 data.m_Size = aStream.ReadU16();
430
431 ReadCond( aStream, aVer, data.m_Unknown2 );
432
433 wxLogTrace( traceAllegroParserBlocks, wxT( " Parsed block 0x03: subtype %#02x, size %d" ), data.m_SubType,
434 data.m_Size );
435
436 switch( data.m_SubType )
437 {
438 case 0x65:
439 // Nothing for this one?
440 break;
441 case 0x64:
442 case 0x66:
443 case 0x67:
444 case 0x6A:
445 {
446 data.m_Substruct = aStream.ReadU32();
447 break;
448 }
449 case 0x69:
450 {
451 data.m_Substruct = std::array<uint32_t, 2>{
452 aStream.ReadU32(),
453 aStream.ReadU32(),
454 };
455 break;
456 }
457 case 0x68:
458 case 0x6B:
459 case 0x6D:
460 case 0x6E:
461 case 0x6F:
462 case 0x71:
463 case 0x73:
464 case 0x78:
465 {
466 data.m_Substruct = aStream.ReadStringFixed( data.m_Size, true );
467 break;
468 }
469 case 0x6C:
470 {
472 sub.m_NumEntries = aStream.ReadU32();
473
474 if( sub.m_NumEntries > 1000000 )
475 {
476 THROW_IO_ERRORF( wxT( "Block 0x03 subtype 0x6C entry count %u exceeds limit at offset %#010zx" ),
477 sub.m_NumEntries, aStream.Position() );
478 }
479
480 sub.m_Entries.reserve( sub.m_NumEntries );
481 for( uint32_t i = 0; i < sub.m_NumEntries; ++i )
482 {
483 sub.m_Entries.push_back( aStream.ReadU32() );
484 }
485
486 data.m_Substruct = std::move( sub );
487 break;
488 }
489 case 0x70:
490 case 0x74:
491 {
493
494 sub.m_X0 = aStream.ReadU16();
495 sub.m_X1 = aStream.ReadU16();
496
497 const size_t numEntries = ( sub.m_X1 + 4 * sub.m_X0 );
498 sub.m_Entries.reserve( numEntries );
499 for( size_t i = 0; i < numEntries; ++i )
500 {
501 sub.m_Entries.push_back( aStream.ReadU8() );
502 }
503 data.m_Substruct = std::move( sub );
504 break;
505 }
506 case 0xF6:
507 {
509 for( size_t i = 0; i < sub.m_Entries.size(); ++i )
510 {
511 sub.m_Entries[i] = aStream.ReadU32();
512 }
513 data.m_Substruct = std::move( sub );
514 break;
515 }
516 default:
517 {
518 if( data.m_Size == 4 )
519 {
520 data.m_Substruct = aStream.ReadU32();
521 }
522 else if( data.m_Size == 8 )
523 {
524 std::array<uint32_t, 2> sub;
525 sub[0] = aStream.ReadU32();
526 sub[1] = aStream.ReadU32();
527 data.m_Substruct = std::move( sub );
528 }
529 else
530 {
531 THROW_IO_ERRORF( wxT( "Unknown substruct type %#02x with size %d" ), data.m_SubType, data.m_Size );
532 }
533 break;
534 }
535 }
536
537 return block;
538}
539
540
541static std::unique_ptr<BLOCK_BASE> ParseBlock_0x04_NET_ASSIGNMENT( FILE_STREAM& aStream, FMT_VER aVer )
542{
543 auto block = std::make_unique<BLOCK<BLK_0x04_NET_ASSIGNMENT>>( aStream.Position() );
544
545 auto& data = block->GetData();
546
547 data.m_Type = aStream.ReadU8();
548 data.m_R = aStream.ReadU16();
549 data.m_Key = aStream.ReadU32();
550 block->SetKey( data.m_Key );
551 data.m_Next = aStream.ReadU32();
552 block->SetNext( data.m_Next );
553 data.m_Net = aStream.ReadU32();
554 data.m_ConnItem = aStream.ReadU32();
555
556 ReadCond( aStream, aVer, data.m_Unknown );
557
558 return block;
559}
560
561
562static std::unique_ptr<BLOCK_BASE> ParseBlock_0x05_TRACK( FILE_STREAM& aStream, FMT_VER aVer )
563{
564 auto block = std::make_unique<BLOCK<BLK_0x05_TRACK>>( aStream.Position() );
565
566 auto& data = block->GetData();
567
568 aStream.Skip( 1 );
569
570 data.m_Layer = ParseLayerInfo( aStream );
571 data.m_Key = aStream.ReadU32();
572 block->SetKey( data.m_Key );
573 data.m_Next = aStream.ReadU32();
574 block->SetNext( data.m_Next );
575 data.m_NetAssignment = aStream.ReadU32();
576 data.m_UnknownPtr1 = aStream.ReadU32();
577 data.m_Unknown2 = aStream.ReadU32();
578 data.m_Unknown3 = aStream.ReadU32();
579 data.m_UnknownPtr2a = aStream.ReadU32();
580 data.m_UnknownPtr2b = aStream.ReadU32();
581 data.m_Unknown4 = aStream.ReadU32();
582 data.m_UnknownPtr3a = aStream.ReadU32();
583 data.m_UnknownPtr3b = aStream.ReadU32();
584
585 ReadCond( aStream, aVer, data.m_Unknown5a );
586 ReadCond( aStream, aVer, data.m_Unknown5b );
587
588 data.m_FirstSegPtr = aStream.ReadU32();
589 data.m_UnknownPtr5 = aStream.ReadU32();
590 data.m_Unknown6 = aStream.ReadU32();
591
592 return block;
593}
594
595
596static std::unique_ptr<BLOCK_BASE> ParseBlock_0x06( FILE_STREAM& stream, FMT_VER aVer )
597{
598 auto block = std::make_unique<BLOCK<BLK_0x06_COMPONENT>>( stream.Position() );
599
600 auto& data = block->GetData();
601
602 stream.Skip( 3 );
603
604 data.m_Key = stream.ReadU32();
605 block->SetKey( data.m_Key );
606 data.m_Next = stream.ReadU32();
607 block->SetNext( data.m_Next );
608 data.m_CompDeviceType = stream.ReadU32();
609 data.m_SymbolName = stream.ReadU32();
610 data.m_FirstInstPtr = stream.ReadU32();
611 data.m_PtrFunctionSlot = stream.ReadU32();
612 data.m_PtrPinNumber = stream.ReadU32();
613 data.m_Fields = stream.ReadU32();
614
615 ReadCond( stream, aVer, data.m_Unknown1 );
616
617 return block;
618}
619
620
621static std::unique_ptr<BLOCK_BASE> ParseBlock_0x07( FILE_STREAM& stream, FMT_VER aVer )
622{
623 auto block = std::make_unique<BLOCK<BLK_0x07_COMPONENT_INST>>( stream.Position() );
624
625 auto& data = block->GetData();
626
627 stream.Skip( 3 );
628
629 data.m_Key = stream.ReadU32();
630 block->SetKey( data.m_Key );
631 data.m_Next = stream.ReadU32();
632 block->SetNext( data.m_Next );
633
634 ReadCond( stream, aVer, data.m_UnknownPtr1 );
635 ReadCond( stream, aVer, data.m_Unknown2 );
636 ReadCond( stream, aVer, data.m_Unknown3 );
637
638 data.m_FpInstPtr = stream.ReadU32();
639
640 ReadCond( stream, aVer, data.m_Unknown4 );
641
642 data.m_RefDesStrPtr = stream.ReadU32();
643 data.m_FunctionInstPtr = stream.ReadU32();
644 data.m_X03Ptr = stream.ReadU32();
645 data.m_Unknown5 = stream.ReadU32();
646 data.m_FirstPadPtr = stream.ReadU32();
647
648 return block;
649}
650
651
652static std::unique_ptr<BLOCK_BASE> ParseBlock_0x08( FILE_STREAM& aStream, FMT_VER aVer )
653{
654 auto block = std::make_unique<BLOCK<BLK_0x08_PIN_NUMBER>>( aStream.Position() );
655
656 auto& data = block->GetData();
657
658 data.m_Type = aStream.ReadU8();
659 data.m_R = aStream.ReadU16();
660 data.m_Key = aStream.ReadU32();
661 block->SetKey( data.m_Key );
662
663 ReadCond( aStream, aVer, data.m_Previous );
664 ReadCond( aStream, aVer, data.m_StrPtr16x );
665
666 data.m_Next = aStream.ReadU32();
667 block->SetNext( data.m_Next );
668
669 ReadCond( aStream, aVer, data.m_StrPtr );
670
671 data.m_PinNamePtr = aStream.ReadU32();
672
673 ReadCond( aStream, aVer, data.m_Unknown1 );
674
675 data.m_Ptr4 = aStream.ReadU32();
676
677 return block;
678}
679
680
681static std::unique_ptr<BLOCK_BASE> ParseBlock_0x09( FILE_STREAM& aStream, FMT_VER aVer )
682{
683 auto block = std::make_unique<BLOCK<BLK_0x09_FILL_LINK>>( aStream.Position() );
684
685 auto& data = block->GetData();
686
687 aStream.Skip( 3 );
688
689 data.m_Key = aStream.ReadU32();
690 block->SetKey( data.m_Key );
691
692 for( size_t i = 0; i < data.m_UnknownArray.size(); ++i )
693 {
694 data.m_UnknownArray[i] = aStream.ReadU32();
695 }
696
697 ReadCond( aStream, aVer, data.m_Unknown1 );
698
699 data.m_UnknownPtr1 = aStream.ReadU32();
700 data.m_UnknownPtr2 = aStream.ReadU32();
701 data.m_Unknown2 = aStream.ReadU32();
702 data.m_UnknownPtr3 = aStream.ReadU32();
703 data.m_UnknownPtr4 = aStream.ReadU32();
704
705 ReadCond( aStream, aVer, data.m_Unknown3 );
706
707 return block;
708}
709
710
711static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0A_DRC( FILE_STREAM& aStream, FMT_VER aVer )
712{
713 auto block = std::make_unique<BLOCK<BLK_0x0A_DRC>>( aStream.Position() );
714
715 auto& data = block->GetData();
716
717 data.m_T = aStream.ReadU8();
718 data.m_Layer = ParseLayerInfo( aStream );
719 data.m_Key = aStream.ReadU32();
720 block->SetKey( data.m_Key );
721 data.m_Next = aStream.ReadU32();
722 block->SetNext( data.m_Next );
723 data.m_Unknown1 = aStream.ReadU32();
724
725 ReadCond( aStream, aVer, data.m_Unknown2 );
726
727 for( size_t i = 0; i < data.m_Coords.size(); ++i )
728 {
729 data.m_Coords[i] = aStream.ReadS32();
730 }
731
732 ReadArrayU32( aStream, data.m_Unknown4 );
733 ReadArrayU32( aStream, data.m_Unknown5 );
734
735 ReadCond( aStream, aVer, data.m_Unknown6 );
736
737 return block;
738}
739
740
741static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0C( FILE_STREAM& aStream, FMT_VER aVer )
742{
743 auto block = std::make_unique<BLOCK<BLK_0x0C_PIN_DEF>>( aStream.Position() );
744
745 auto& data = block->GetData();
746
747 data.m_T = aStream.ReadU8();
748 data.m_Layer = ParseLayerInfo( aStream );
749
750 data.m_Key = aStream.ReadU32();
751 block->SetKey( data.m_Key );
752 data.m_Next = aStream.ReadU32();
753 block->SetNext( data.m_Next );
754
755 data.m_Unknown1 = aStream.ReadU32();
756 data.m_Unknown2 = aStream.ReadU32();
757
758 // Older packed format
759 ReadCond( aStream, aVer, data.m_Shape );
760 ReadCond( aStream, aVer, data.m_DrillChar );
761 ReadCond( aStream, aVer, data.m_UnknownPadding );
762
763 // V17.2+
764 ReadCond( aStream, aVer, data.m_Shape16x );
765 ReadCond( aStream, aVer, data.m_DrillChars );
766 ReadCond( aStream, aVer, data.m_Unknown_16x );
767
768 data.m_Unknown4 = aStream.ReadU32();
769 ReadCond( aStream, aVer, data.m_Unknown5 );
770
771 for( size_t i = 0; i < data.m_Coords.size(); ++i )
772 {
773 data.m_Coords[i] = aStream.ReadS32();
774 }
775
776 for( size_t i = 0; i < data.m_Size.size(); ++i )
777 {
778 data.m_Size[i] = aStream.ReadS32();
779 }
780
781 data.m_GroupPtr = aStream.ReadU32();
782 data.m_Unknown6 = aStream.ReadU32();
783 data.m_Unknown7 = aStream.ReadU32();
784
785 ReadCond( aStream, aVer, data.m_Unknown8 );
786
787 return block;
788}
789
790
791static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0D_PAD( FILE_STREAM& aStream, FMT_VER aVer )
792{
793 auto block = std::make_unique<BLOCK<BLK_0x0D_PAD>>( aStream.Position() );
794
795 auto& data = block->GetData();
796
797 aStream.Skip( 3 );
798
799 data.m_Key = aStream.ReadU32();
800 block->SetKey( data.m_Key );
801 data.m_NameStrId = aStream.ReadU32();
802 data.m_Next = aStream.ReadU32();
803 block->SetNext( data.m_Next );
804
805 ReadCond( aStream, aVer, data.m_Unknown1 );
806
807 data.m_CoordsX = aStream.ReadS32();
808 data.m_CoordsY = aStream.ReadS32();
809
810 data.m_PadStack = aStream.ReadU32();
811 data.m_Unknown2 = aStream.ReadU32();
812
813 ReadCond( aStream, aVer, data.m_Unknown3 );
814
815 data.m_Flags = aStream.ReadU32();
816 data.m_Rotation = aStream.ReadU32();
817
818 return block;
819}
820
821
822static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0E( FILE_STREAM& aStream, FMT_VER aVer )
823{
824 auto block = std::make_unique<BLOCK<BLK_0x0E_RECT>>( aStream.Position() );
825
826 auto& data = block->GetData();
827
828 data.m_T = aStream.ReadU8();
829 data.m_Layer = ParseLayerInfo( aStream );
830 data.m_Key = aStream.ReadU32();
831 block->SetKey( data.m_Key );
832 data.m_Next = aStream.ReadU32();
833 block->SetNext( data.m_Next );
834 data.m_FpPtr = aStream.ReadU32();
835
836 data.m_Unknown1 = aStream.ReadU32();
837 data.m_Unknown2 = aStream.ReadU32();
838 data.m_Unknown3 = aStream.ReadU32();
839
840 ReadCond( aStream, aVer, data.m_Unknown4 );
841 ReadCond( aStream, aVer, data.m_Unknown5 );
842
843 for( size_t i = 0; i < data.m_Coords.size(); ++i )
844 {
845 data.m_Coords[i] = aStream.ReadS32();
846 }
847
848 for( size_t i = 0; i < data.m_UnknownArr.size(); ++i )
849 {
850 data.m_UnknownArr[i] = aStream.ReadU32();
851 }
852
853 data.m_Rotation = aStream.ReadU32();
854
855 return block;
856}
857
858
859static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0F( FILE_STREAM& stream, FMT_VER aVer )
860{
861 auto block = std::make_unique<BLOCK<BLK_0x0F_FUNCTION_SLOT>>( stream.Position() );
862
863 auto& data = block->GetData();
864
865 stream.Skip( 3 );
866
867 data.m_Key = stream.ReadU32();
868 block->SetKey( data.m_Key );
869 data.m_SlotName = stream.ReadU32();
870
871 ReadCond( stream, aVer, data.m_Unknown1 );
872
873 if( aVer < FMT_VER::V_190 )
874 stream.ReadBytes( data.m_CompDeviceType.data(), data.m_CompDeviceType.size() );
875
876 ReadCond( stream, aVer, data.m_CompDeviceTypePtr );
877
878 ReadCond( stream, aVer, data.m_Next );
879 block->SetNext( data.m_Next.value_or( 0 ) );
880
881 data.m_Ptr0x06 = stream.ReadU32();
882 data.m_Ptr0x11 = stream.ReadU32();
883 data.m_Unknown2 = stream.ReadU32();
884
885 return block;
886}
887
888
889static std::unique_ptr<BLOCK_BASE> ParseBlock_0x10( FILE_STREAM& stream, FMT_VER aVer )
890{
891 auto block = std::make_unique<BLOCK<BLK_0x10_FUNCTION_INST>>( stream.Position() );
892
893 auto& data = block->GetData();
894
895 stream.Skip( 3 );
896
897 data.m_Key = stream.ReadU32();
898 block->SetKey( data.m_Key );
899
900 ReadCond( stream, aVer, data.m_Unknown1 );
901 data.m_ComponentInstPtr = stream.ReadU32();
902 ReadCond( stream, aVer, data.m_Unknown2 );
903 data.m_PtrX12 = stream.ReadU32();
904 data.m_Unknown3 = stream.ReadU32();
905 data.m_FunctionName = stream.ReadU32();
906 data.m_Slots = stream.ReadU32();
907 data.m_Fields = stream.ReadU32();
908
909 return block;
910}
911
912
913static std::unique_ptr<BLOCK_BASE> ParseBlock_0x11( FILE_STREAM& aStream, FMT_VER aVer )
914{
915 auto block = std::make_unique<BLOCK<BLK_0x11_PIN_NAME>>( aStream.Position() );
916
917 auto& data = block->GetData();
918
919 data.m_Type = aStream.ReadU8();
920 data.m_R = aStream.ReadU16();
921 data.m_Key = aStream.ReadU32();
922 block->SetKey( data.m_Key );
923 data.m_PinNameStrPtr = aStream.ReadU32();
924 data.m_Next = aStream.ReadU32();
925 block->SetNext( data.m_Next );
926 data.m_PinNumberPtr = aStream.ReadU32();
927 data.m_Unknown1 = aStream.ReadU32();
928
929 ReadCond( aStream, aVer, data.m_Unknown2 );
930
931 return block;
932}
933
934
935static std::unique_ptr<BLOCK_BASE> ParseBlock_0x12( FILE_STREAM& aStream, FMT_VER aVer )
936{
937 auto block = std::make_unique<BLOCK<BLK_0x12_XREF>>( aStream.Position() );
938
939 auto& data = block->GetData();
940
941 data.m_Type = aStream.ReadU8();
942 data.m_R = aStream.ReadU16();
943 data.m_Key = aStream.ReadU32();
944 block->SetKey( data.m_Key );
945 data.m_Ptr1 = aStream.ReadU32();
946 data.m_Ptr2 = aStream.ReadU32();
947 data.m_Ptr3 = aStream.ReadU32();
948 data.m_Unknown1 = aStream.ReadU32();
949
950 ReadCond( aStream, aVer, data.m_Unknown2 );
951 ReadCond( aStream, aVer, data.m_Unknown3 );
952
953 return block;
954}
955
956
957static std::unique_ptr<BLOCK_BASE> ParseBlock_0x14( FILE_STREAM& aStream, FMT_VER aVer )
958{
959 auto block = std::make_unique<BLOCK<BLK_0x14_GRAPHIC>>( aStream.Position() );
960
961 auto& data = block->GetData();
962
963 data.m_Type = aStream.ReadU8();
964 data.m_Layer = ParseLayerInfo( aStream );
965 data.m_Key = aStream.ReadU32();
966 block->SetKey( data.m_Key );
967 data.m_Next = aStream.ReadU32();
968 block->SetNext( data.m_Next );
969 data.m_Parent = aStream.ReadU32();
970 data.m_Flags = aStream.ReadU32();
971
972 ReadCond( aStream, aVer, data.m_Unknown2 );
973
974 data.m_SegmentPtr = aStream.ReadU32();
975 data.m_Ptr0x03 = aStream.ReadU32();
976 data.m_Ptr0x26 = aStream.ReadU32();
977
978 return block;
979}
980
981
982static std::unique_ptr<BLOCK_BASE> ParseBlock_0x15_16_17_SEGMENT( FILE_STREAM& aStream, FMT_VER aVer, uint8_t aType )
983{
984 auto block = std::make_unique<BLOCK<BLK_0x15_16_17_SEGMENT>>( aType, aStream.Position() );
985
986 auto& data = block->GetData();
987
988 aStream.Skip( 3 );
989
990 data.m_Key = aStream.ReadU32();
991 block->SetKey( data.m_Key );
992 data.m_Next = aStream.ReadU32();
993 block->SetNext( data.m_Next );
994 data.m_Parent = aStream.ReadU32();
995 data.m_Flags = aStream.ReadU32();
996
997 ReadCond( aStream, aVer, data.m_Unknown2 );
998
999 data.m_Width = aStream.ReadU32();
1000
1001 data.m_StartX = aStream.ReadS32();
1002 data.m_StartY = aStream.ReadS32();
1003 data.m_EndX = aStream.ReadS32();
1004 data.m_EndY = aStream.ReadS32();
1005
1006 return block;
1007}
1008
1009
1010static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1A( FILE_STREAM& aStream, FMT_VER aVer )
1011{
1012 auto block = std::make_unique<BLOCK<BLK_0x1A_UNKNOWN>>( aStream.Position() );
1013
1014 auto& data = block->GetData();
1015
1016 data.m_Type = aStream.ReadU8();
1017 data.m_T2 = aStream.ReadU16();
1018 data.m_Key = aStream.ReadU32();
1019 block->SetKey( data.m_Key );
1020
1021 ReadArrayU32( aStream, data.m_UnknownArray );
1022
1023 return block;
1024}
1025
1026
1027static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1B_NET( FILE_STREAM& stream, FMT_VER aVer )
1028{
1029 auto block = std::make_unique<BLOCK<BLK_0x1B_NET>>( stream.Position() );
1030
1031 auto& data = block->GetData();
1032
1033 stream.Skip( 3 );
1034
1035 data.m_Key = stream.ReadU32();
1036 block->SetKey( data.m_Key );
1037 data.m_Next = stream.ReadU32();
1038 block->SetNext( data.m_Next );
1039 data.m_NetName = stream.ReadU32();
1040 data.m_Unknown1 = stream.ReadU32();
1041
1042 ReadCond( stream, aVer, data.m_Unknown2 );
1043
1044 data.m_Type = stream.ReadU32();
1045 data.m_Assignment = stream.ReadU32();
1046 data.m_Ratline = stream.ReadU32();
1047 data.m_FieldsPtr = stream.ReadU32();
1048 data.m_MatchGroupPtr = stream.ReadU32();
1049 data.m_ModelPtr = stream.ReadU32();
1050 data.m_UnknownPtr4 = stream.ReadU32();
1051 data.m_UnknownPtr5 = stream.ReadU32();
1052 data.m_UnknownPtr6 = stream.ReadU32();
1053
1054 return block;
1055}
1056
1057
1058static PAD_TYPE decodePadType( uint8_t aVal )
1059{
1060 // clang-format off
1061 switch( (aVal & 0xF0) )
1062 {
1063 case 0x00:
1064 return PAD_TYPE::THROUGH_VIA;
1065 case 0x10:
1066 return PAD_TYPE::VIA;
1067 break;
1068 case 0x20:
1069 case 0xa0: // Unclear what the difference is
1070 return PAD_TYPE::SMD_PIN;
1071 case 0x30:
1072 return PAD_TYPE::SLOT;
1073 break;
1074 case 0x80:
1075 return PAD_TYPE::NPTH;
1076 break;
1077 default:
1078 THROW_IO_ERRORF( wxT( "Unknown padstack type 0x%x" ), aVal );
1079 break;
1080 }
1081};
1082
1083
1084static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1C_PADSTACK( FILE_STREAM& aStream, FMT_VER aVer )
1085{
1086 auto block = std::make_unique<BLOCK<BLK_0x1C_PADSTACK>>( aStream.Position() );
1087
1088 auto& data = block->GetData();
1089
1090 data.m_UnknownByte1 = aStream.ReadU8();
1091 data.m_N = aStream.ReadU8();
1092 data.m_StartLayer = aStream.ReadU8();
1093
1094 data.m_Key = aStream.ReadU32();
1095 block->SetKey( data.m_Key );
1096 data.m_Next = aStream.ReadU32();
1097 block->SetNext( data.m_Next );
1098 data.m_PadStr = aStream.ReadU32();
1099
1100 if( aVer < FMT_VER::V_172 )
1101 {
1102 BLK_0x1C_PADSTACK::HEADER_v16x& hdr = data.m_Header.emplace<BLK_0x1C_PADSTACK::HEADER_v16x>();
1103
1104 hdr.m_DrillSize = aStream.ReadU32();
1105 hdr.m_UnknownStr = aStream.ReadU32();
1106 hdr.m_DrillMarkSizeX = aStream.ReadU32();
1107 hdr.m_DrillMarkSizeY = aStream.ReadU32();
1108 hdr.m_DrillOffsetX = aStream.ReadU32();
1109 hdr.m_DrillOffsetY = aStream.ReadU32();
1110
1111 hdr.m_DrillMarkShape = aStream.ReadU8();
1112 hdr.m_Flags = aStream.ReadU8();
1113 hdr.m_DrillChar = aStream.ReadU8();
1114 hdr.m_D = aStream.ReadU8();
1115 hdr.m_Unknown_1 = aStream.ReadU16();
1116
1117 hdr.m_ArrayNX = aStream.ReadU16();
1118 hdr.m_ArrayNY = aStream.ReadU16();
1119
1120 hdr.m_LayerCount = aStream.ReadU16();
1121 hdr.m_ClearanceX = aStream.ReadU32();
1122 hdr.m_ClearanceY = aStream.ReadU32();
1123 hdr.m_TolerancePos = aStream.ReadU32();
1124 hdr.m_ToleranceNeg = aStream.ReadU32();
1125
1126 hdr.m_Unknown_2 = aStream.ReadU32();
1127 hdr.m_SlotX = aStream.ReadU32();
1128 hdr.m_SlotY = aStream.ReadU32();
1129 hdr.m_Unknown_3 = aStream.ReadU32();
1130
1131 ReadCond( aStream, aVer, hdr.m_Unknown_4 );
1132 }
1133 else
1134 {
1135 BLK_0x1C_PADSTACK::HEADER_v17x& hdr = data.m_Header.emplace<BLK_0x1C_PADSTACK::HEADER_v17x>();
1136
1137 hdr.m_UnknownStr = aStream.ReadU32();
1138 hdr.m_Unknown1 = aStream.ReadU32();
1139 hdr.m_Unknown2 = aStream.ReadU32();
1140
1141 uint8_t padTypeAndA = aStream.ReadU8();
1142 hdr.m_PadType = decodePadType( padTypeAndA );
1143 hdr.m_A = ( padTypeAndA & 0x0F );
1144
1145 hdr.m_B = aStream.ReadU8();
1146 hdr.m_Flags = aStream.ReadU8();
1147 hdr.m_D = aStream.ReadU8();
1148
1149 hdr.m_unknown3 = aStream.ReadU32();
1150 hdr.m_Unknown4 = aStream.ReadU32();
1151 hdr.m_ArrayNX = aStream.ReadU16();
1152 hdr.m_ArrayNY = aStream.ReadU16();
1153 hdr.m_LayerCount = aStream.ReadU16();
1154 hdr.m_Unknown5 = aStream.ReadU16();
1155
1156 hdr.m_ClearanceX = aStream.ReadU32();
1157 hdr.m_ClearanceY = aStream.ReadU32();
1158
1159 hdr.m_Unknown6a = aStream.ReadU32();
1160 hdr.m_Unknown6b = aStream.ReadU32();
1161
1162 hdr.m_DrillSize = aStream.ReadU32();
1163 hdr.m_TolerancePos = aStream.ReadU32();
1164 hdr.m_ToleranceNeg = aStream.ReadU32();
1165
1166 hdr.m_SlotX = aStream.ReadU32();
1167 hdr.m_SlotY = aStream.ReadU32();
1168
1169 hdr.m_ToleranceTravelPos = aStream.ReadU32();
1170 hdr.m_ToleranceTravelNeg = aStream.ReadU32();
1171
1172 hdr.m_DrillMarkSizeX = aStream.ReadU32();
1173 hdr.m_DrillMarkSizeY = aStream.ReadU32();
1174 hdr.m_DrillMarkShape = aStream.ReadU32();
1175 hdr.m_DrillChars = aStream.ReadU32();
1176
1177 ReadArrayU32( aStream, hdr.m_UnknownArr3 );
1178
1179 ReadCond( aStream, aVer, hdr.m_UnknownArr_v180 );
1180 }
1181
1182 // Chekc the layer count isn't massive - malformed files could make this huge
1183 static const uint16_t MAX_LAYER_COUNT = 256;
1184 if( data.GetLayerCount() > MAX_LAYER_COUNT )
1185 throw std::runtime_error( "Layer count exceeds maximum of " + std::to_string( MAX_LAYER_COUNT ) );
1186
1187 // Work out how many fixed slots we have
1188 if( aVer < FMT_VER::V_165 )
1189 data.m_NumFixedCompEntries = 10;
1190 else if( aVer < FMT_VER::V_172 )
1191 data.m_NumFixedCompEntries = 11;
1192 else
1193 data.m_NumFixedCompEntries = 21;
1194
1195 // ...and how many per-layer slots
1196 data.m_NumCompsPerLayer = aVer < FMT_VER::V_172 ? 3 : 4;
1197
1198 const size_t nComps = data.m_NumFixedCompEntries + ( data.GetLayerCount() * data.m_NumCompsPerLayer );
1199
1200 data.m_Components.reserve( nComps );
1201 for( size_t i = 0; i < nComps; ++i )
1202 {
1203 PADSTACK_COMPONENT& comp = data.m_Components.emplace_back();
1204
1205 comp.m_Type = aStream.ReadU8();
1206
1207 comp.m_UnknownByte1 = aStream.ReadU8();
1208 comp.m_UnknownByte2 = aStream.ReadU8();
1209 comp.m_UnknownByte3 = aStream.ReadU8();
1210
1211 ReadCond( aStream, aVer, comp.m_Unknown1 );
1212
1213 comp.m_W = aStream.ReadS32();
1214 comp.m_H = aStream.ReadS32();
1215
1216 ReadCond( aStream, aVer, comp.m_Z1 );
1217
1218 comp.m_OffsetX = aStream.ReadS32();
1219 comp.m_OffsetY = aStream.ReadS32();
1220
1221 if( aVer >= FMT_VER::V_172 )
1222 {
1223 comp.m_Z2 = aStream.ReadU32();
1224 comp.m_ShapePtr = aStream.ReadU32();
1225 }
1226 else
1227 {
1228 comp.m_ShapePtr = aStream.ReadU32();
1229
1230 if(i < nComps - 1)
1231 comp.m_Z2 = aStream.ReadU32();
1232 }
1233 }
1234
1235 {
1236 const size_t nElems = data.m_N * ( ( aVer < FMT_VER::V_172 ) ? 8 : 10 );
1237
1238 data.m_UnknownArrN.reserve( nElems );
1239 for( size_t i = 0; i < nElems; ++i )
1240 {
1241 data.m_UnknownArrN.push_back( aStream.ReadU32() );
1242 }
1243 }
1244
1245 return block;
1246}
1247
1248
1249static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1D( FILE_STREAM& aStream, FMT_VER aVer )
1250{
1251 auto block = std::make_unique<BLOCK<BLK_0x1D_CONSTRAINT_SET>>( aStream.Position() );
1252
1253 auto& data = block->GetData();
1254
1255 aStream.Skip( 3 );
1256
1257 data.m_Key = aStream.ReadU32();
1258 block->SetKey( data.m_Key );
1259 data.m_Next = aStream.ReadU32();
1260 block->SetNext( data.m_Next );
1261 data.m_NameStrKey = aStream.ReadU32();
1262 data.m_FieldPtr = aStream.ReadU32();
1263
1264 data.m_SizeA = aStream.ReadU16();
1265 data.m_SizeB = aStream.ReadU16();
1266
1267 data.m_DataB.resize( data.m_SizeB );
1268
1269 // This version stores 12 values per copper layer where later ones store 14
1270 const size_t layerRecordSize = aVer == FMT_VER::V_161 ? 48 : sizeof( data.m_DataB[0] );
1271
1272 for( auto& item : data.m_DataB )
1273 {
1274 item.fill( 0 );
1275 aStream.ReadBytes( item.data(), layerRecordSize );
1276 }
1277
1278 data.m_DataA.resize( data.m_SizeA );
1279
1280 for( auto& item : data.m_DataA )
1281 aStream.ReadBytes( item.data(), item.size() );
1282
1283 ReadCond( aStream, aVer, data.m_Unknown4 );
1284
1285 return block;
1286}
1287
1288
1289static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1E( FILE_STREAM& aStream, FMT_VER aVer )
1290{
1291 auto block = std::make_unique<BLOCK<BLK_0x1E_SI_MODEL>>( aStream.Position() );
1292
1293 auto& data = block->GetData();
1294
1295 data.m_Type = aStream.ReadU8();
1296 data.m_T2 = aStream.ReadU16();
1297 data.m_Key = aStream.ReadU32();
1298 block->SetKey( data.m_Key );
1299 data.m_Next = aStream.ReadU32();
1300 block->SetNext( data.m_Next );
1301
1302 ReadCond( aStream, aVer, data.m_Unknown2 );
1303 ReadCond( aStream, aVer, data.m_Unknown3 );
1304
1305 data.m_StrPtr = aStream.ReadU32();
1306 data.m_Size = aStream.ReadU32();
1307
1308 data.m_String = aStream.ReadStringFixed( data.m_Size, true );
1309
1310 ReadCond( aStream, aVer, data.m_Unknown4 );
1311
1312 return block;
1313}
1314
1315
1316static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1F( FILE_STREAM& aStream, FMT_VER aVer )
1317{
1318 auto block = std::make_unique<BLOCK<BLK_0x1F_PADSTACK_DIM>>( aStream.Position() );
1319
1320 auto& data = block->GetData();
1321
1322 aStream.Skip( 3 );
1323
1324 data.m_Key = aStream.ReadU32();
1325 block->SetKey( data.m_Key );
1326
1327 data.m_Next = aStream.ReadU32();
1328 block->SetNext( data.m_Next );
1329 data.m_Unknown2 = aStream.ReadU32();
1330 data.m_Unknown3 = aStream.ReadU32();
1331 data.m_Unknown4 = aStream.ReadU32();
1332 data.m_Unknown5 = aStream.ReadU16();
1333
1334 data.m_Size = aStream.ReadU16();
1335
1336 size_t substructSize = 0;
1337 if( aVer >= FMT_VER::V_175 )
1338 substructSize = data.m_Size * 384 + 8;
1339 else if( aVer >= FMT_VER::V_172 )
1340 substructSize = data.m_Size * 280 + 8;
1341 else if( aVer >= FMT_VER::V_162 )
1342 substructSize = data.m_Size * 280 + 4;
1343 else
1344 substructSize = data.m_Size * 240 + 4;
1345
1346 data.m_Substruct.resize( substructSize );
1347 aStream.ReadBytes( data.m_Substruct.data(), substructSize );
1348
1349 return block;
1350}
1351
1352
1353static std::unique_ptr<BLOCK_BASE> ParseBlock_0x20( FILE_STREAM& aStream, FMT_VER aVer )
1354{
1355 auto block = std::make_unique<BLOCK<BLK_0x20_UNKNOWN>>( aStream.Position() );
1356
1357 auto& data = block->GetData();
1358
1359 data.m_Type = aStream.ReadU8();
1360 data.m_R = aStream.ReadU16();
1361 data.m_Key = aStream.ReadU32();
1362 block->SetKey( data.m_Key );
1363 data.m_Next = aStream.ReadU32();
1364 block->SetNext( data.m_Next );
1365
1366 ReadArrayU32( aStream, data.m_UnknownArray1 );
1367 ReadCond( aStream, aVer, data.m_UnknownArray2 );
1368
1369 return block;
1370}
1371
1372
1373static std::unique_ptr<BLOCK_BASE> ParseBlock_0x21( FILE_STREAM& aStream, FMT_VER aVer )
1374{
1375 auto block = std::make_unique<BLOCK<BLK_0x21_BLOB>>( aStream.Position() );
1376
1377 auto& data = block->GetData();
1378
1379 data.m_Type = aStream.ReadU8();
1380 data.m_R = aStream.ReadU16();
1381
1382 data.m_Size = aStream.ReadU32();
1383
1384 if( data.m_Size < 12 )
1385 {
1386 THROW_IO_ERRORF( wxT( "Block 0x21 size %u too small (minimum 12) at offset %#010zx" ),
1387 data.m_Size, aStream.Position() );
1388 }
1389
1390 data.m_Key = aStream.ReadU32();
1391 block->SetKey( data.m_Key );
1392
1393 const size_t nBytes = data.m_Size - 12;
1394 data.m_Data.resize( nBytes );
1395 aStream.ReadBytes( data.m_Data.data(), nBytes );
1396
1397 return block;
1398}
1399
1400
1401static std::unique_ptr<BLOCK_BASE> ParseBlock_0x22( FILE_STREAM& aStream, FMT_VER aVer )
1402{
1403 auto block = std::make_unique<BLOCK<BLK_0x22_UNKNOWN>>( aStream.Position() );
1404
1405 auto& data = block->GetData();
1406
1407 data.m_Type = aStream.ReadU8();
1408 data.m_T2 = aStream.ReadU16();
1409 data.m_Key = aStream.ReadU32();
1410 block->SetKey( data.m_Key );
1411
1412 ReadCond( aStream, aVer, data.m_Unknown1 );
1413
1414 ReadArrayU32( aStream, data.m_UnknownArray );
1415
1416 return block;
1417}
1418
1419
1420static std::unique_ptr<BLOCK_BASE> ParseBlock_0x23_RATLINE( FILE_STREAM& aStream, FMT_VER aVer )
1421{
1422 auto block = std::make_unique<BLOCK<BLK_0x23_RATLINE>>( aStream.Position() );
1423
1424 auto& data = block->GetData();
1425
1426 data.m_Type = aStream.ReadU8();
1427 data.m_Layer = ParseLayerInfo( aStream );
1428 data.m_Key = aStream.ReadU32();
1429 block->SetKey( data.m_Key );
1430 data.m_Next = aStream.ReadU32();
1431 block->SetNext( data.m_Next );
1432
1433 ReadArrayU32( aStream, data.m_Flags );
1434
1435 data.m_Ptr1 = aStream.ReadU32();
1436 data.m_Ptr2 = aStream.ReadU32();
1437 data.m_Ptr3 = aStream.ReadU32();
1438
1439 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1440 {
1441 data.m_Coords[i] = aStream.ReadS32();
1442 }
1443
1444 ReadArrayU32( aStream, data.m_Unknown1 );
1445
1446 ReadCond( aStream, aVer, data.m_Unknown2 );
1447 ReadCond( aStream, aVer, data.m_Unknown3 );
1448
1449 return block;
1450}
1451
1452
1453static std::unique_ptr<BLOCK_BASE> ParseBlock_0x24_RECT( FILE_STREAM& aStream, FMT_VER aVer )
1454{
1455 auto block = std::make_unique<BLOCK<BLK_0x24_RECT>>( aStream.Position() );
1456
1457 auto& data = block->GetData();
1458
1459 data.m_Type = aStream.ReadU8();
1460 data.m_Layer = ParseLayerInfo( aStream );
1461 data.m_Key = aStream.ReadU32();
1462 block->SetKey( data.m_Key );
1463 data.m_Next = aStream.ReadU32();
1464 block->SetNext( data.m_Next );
1465 data.m_Parent = aStream.ReadU32();
1466 data.m_Unknown1 = aStream.ReadU32();
1467
1468 ReadCond( aStream, aVer, data.m_Unknown2 );
1469
1470 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1471 {
1472 data.m_Coords[i] = aStream.ReadS32();
1473 }
1474
1475 data.m_Ptr2 = aStream.ReadU32();
1476
1477 data.m_Unknown3 = aStream.ReadU32();
1478 data.m_Unknown4 = aStream.ReadU32();
1479 data.m_Rotation = aStream.ReadU32();
1480
1481 return block;
1482}
1483
1484
1485static std::unique_ptr<BLOCK_BASE> ParseBlock_0x26( FILE_STREAM& aStream, FMT_VER aVer )
1486{
1487 auto block = std::make_unique<BLOCK<BLK_0x26_MATCH_GROUP>>( aStream.Position() );
1488
1489 auto& data = block->GetData();
1490
1491 data.m_Type = aStream.ReadU8();
1492 data.m_R = aStream.ReadU16();
1493 data.m_Key = aStream.ReadU32();
1494 block->SetKey( data.m_Key );
1495 data.m_MemberPtr = aStream.ReadU32();
1496
1497 ReadCond( aStream, aVer, data.m_Unknown1 );
1498
1499 data.m_GroupPtr = aStream.ReadU32();
1500 data.m_ConstPtr = aStream.ReadU32();
1501
1502 ReadCond( aStream, aVer, data.m_Unknown2 );
1503
1504 return block;
1505}
1506
1507
1508static std::unique_ptr<BLOCK_BASE> ParseBlock_0x27( FILE_STREAM& aStream, FMT_VER aVer, size_t aEndOff )
1509{
1510 auto block = std::make_unique<BLOCK<BLK_0x27_CSTRMGR_XREF>>( aStream.Position() );
1511
1512 auto& data = block->GetData();
1513
1514 const size_t totalBytes = aEndOff - 1 - aStream.Position();
1515
1516 // The blob starts with 3 bytes of padding, then uint32 LE values
1517 constexpr size_t kPadding = 3;
1518
1519 if( totalBytes <= kPadding )
1520 {
1521 aStream.Skip( totalBytes );
1522 return block;
1523 }
1524
1525 aStream.Skip( kPadding );
1526
1527 const size_t payloadBytes = totalBytes - kPadding;
1528 const size_t numValues = payloadBytes / 4;
1529 const size_t remainder = payloadBytes % 4;
1530
1531 data.m_Refs.resize( numValues );
1532
1533 for( size_t i = 0; i < numValues; i++ )
1534 data.m_Refs[i] = aStream.ReadU32();
1535
1536 if( remainder > 0 )
1537 aStream.Skip( remainder );
1538
1539 return block;
1540}
1541
1542
1543static std::unique_ptr<BLOCK_BASE> ParseBlock_0x28_SHAPE( FILE_STREAM& aStream, FMT_VER aVer )
1544{
1545 auto block = std::make_unique<BLOCK<BLK_0x28_SHAPE>>( aStream.Position() );
1546
1547 auto& data = block->GetData();
1548
1549 data.m_Type = aStream.ReadU8();
1550 data.m_Layer = ParseLayerInfo( aStream );
1551 data.m_Key = aStream.ReadU32();
1552 block->SetKey( data.m_Key );
1553 data.m_Next = aStream.ReadU32();
1554 block->SetNext( data.m_Next );
1555 data.m_Ptr1 = aStream.ReadU32();
1556 data.m_Unknown1 = aStream.ReadU32();
1557
1558 ReadCond( aStream, aVer, data.m_Unknown2 );
1559 ReadCond( aStream, aVer, data.m_Unknown3 );
1560
1561 data.m_Ptr2 = aStream.ReadU32();
1562 data.m_Ptr3 = aStream.ReadU32();
1563 data.m_FirstKeepoutPtr = aStream.ReadU32();
1564 data.m_FirstSegmentPtr = aStream.ReadU32();
1565 data.m_Unknown4 = aStream.ReadU32();
1566 data.m_Unknown5 = aStream.ReadU32();
1567
1568 ReadCond( aStream, aVer, data.m_TablePtr );
1569
1570 data.m_Ptr6 = aStream.ReadU32();
1571
1572 ReadCond( aStream, aVer, data.m_TablePtr_16x );
1573
1574 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1575 {
1576 data.m_Coords[i] = aStream.ReadS32();
1577 }
1578
1579 return block;
1580}
1581
1582
1583static std::unique_ptr<BLOCK_BASE> ParseBlock_0x29_PIN( FILE_STREAM& aStream, FMT_VER aVer )
1584{
1585 auto block = std::make_unique<BLOCK<BLK_0x29_PIN>>( aStream.Position() );
1586
1587 auto& data = block->GetData();
1588
1589 data.m_Type = aStream.ReadU8();
1590 data.m_T = aStream.ReadU16();
1591 data.m_Key = aStream.ReadU32();
1592 block->SetKey( data.m_Key );
1593
1594 data.m_Ptr1 = aStream.ReadU32();
1595 data.m_Ptr2 = aStream.ReadU32();
1596
1597 data.m_Null = aStream.ReadU32();
1598
1599 data.m_Ptr3 = aStream.ReadU32();
1600
1601 data.m_Coord1 = aStream.ReadS32();
1602 data.m_Coord2 = aStream.ReadS32();
1603
1604 data.m_PtrPadstack = aStream.ReadU32();
1605
1606 data.m_Unknown1 = aStream.ReadU32();
1607
1608 data.m_PtrX30 = aStream.ReadU32();
1609
1610 data.m_Unknown2 = aStream.ReadU32();
1611 data.m_Unknown3 = aStream.ReadU32();
1612 data.m_Unknown4 = aStream.ReadU32();
1613
1614 return block;
1615}
1616
1617
1618static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2A( FILE_STREAM& aStream, FMT_VER aVer )
1619{
1620 auto block = std::make_unique<BLOCK<BLK_0x2A_LAYER_LIST>>( aStream.Position() );
1621
1622 auto& data = block->GetData();
1623
1624 aStream.Skip( 1 );
1625
1626 data.m_NumEntries = aStream.ReadU16();
1627
1628 ReadCond( aStream, aVer, data.m_Unknown );
1629
1630 if( data.m_NonRefEntries.exists( aVer ) )
1631 {
1632 data.m_NonRefEntries = std::vector<BLK_0x2A_LAYER_LIST::NONREF_ENTRY>();
1633 data.m_NonRefEntries->reserve( data.m_NumEntries );
1634 for( size_t i = 0; i < data.m_NumEntries; ++i )
1635 {
1636 BLK_0x2A_LAYER_LIST::NONREF_ENTRY& entry = data.m_NonRefEntries->emplace_back();
1637
1638 entry.m_Name = aStream.ReadStringFixed( 32, true );
1639 entry.m_Properties = aStream.ReadU32();
1640 }
1641 }
1642 else
1643 {
1644 data.m_RefEntries = std::vector<BLK_0x2A_LAYER_LIST::REF_ENTRY>();
1645 data.m_RefEntries->reserve( data.m_NumEntries );
1646 for( size_t i = 0; i < data.m_NumEntries; ++i )
1647 {
1648 BLK_0x2A_LAYER_LIST::REF_ENTRY& entry = data.m_RefEntries->emplace_back();
1649
1650 entry.mLayerNameId = aStream.ReadU32();
1651 entry.m_Properties = aStream.ReadU32();
1652 entry.m_Unknown = aStream.ReadU32();
1653 }
1654 }
1655
1656 data.m_Key = aStream.ReadU32();
1657 block->SetKey( data.m_Key );
1658
1659 return block;
1660}
1661
1662
1663static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2B( FILE_STREAM& stream, FMT_VER aVer )
1664{
1665 auto block = std::make_unique<BLOCK<BLK_0x2B_FOOTPRINT_DEF>>( stream.Position() );
1666
1667 auto& data = block->GetData();
1668
1669 stream.Skip( 3 );
1670
1671 data.m_Key = stream.ReadU32();
1672 block->SetKey( data.m_Key );
1673 data.m_FpStrRef = stream.ReadU32();
1674 data.m_Unknown1 = stream.ReadU32();
1675 ReadArrayU32( stream, data.m_Coords );
1676 data.m_Next = stream.ReadU32();
1677 block->SetNext( data.m_Next );
1678 data.m_FirstInstPtr = stream.ReadU32();
1679 data.m_UnknownPtr3 = stream.ReadU32();
1680 data.m_UnknownPtr4 = stream.ReadU32();
1681 data.m_UnknownPtr5 = stream.ReadU32();
1682 data.m_FieldsPtr = stream.ReadU32();
1683 data.m_UnknownPtr6 = stream.ReadU32();
1684 data.m_UnknownPtr7 = stream.ReadU32();
1685 data.m_UnknownPtr8 = stream.ReadU32();
1686
1687 ReadCond( stream, aVer, data.m_Unknown2 );
1688 ReadCond( stream, aVer, data.m_Unknown3 );
1689
1690 return block;
1691}
1692
1693
1694static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2C_TABLE( FILE_STREAM& aStream, FMT_VER aVer )
1695{
1696 auto block = std::make_unique<BLOCK<BLK_0x2C_TABLE>>( aStream.Position() );
1697
1698 auto& data = block->GetData();
1699
1700 data.m_Type = aStream.ReadU8();
1701 data.m_SubType = aStream.ReadU16();
1702 data.m_Key = aStream.ReadU32();
1703 block->SetKey( data.m_Key );
1704 data.m_Next = aStream.ReadU32();
1705 block->SetNext( data.m_Next );
1706
1707 ReadCond( aStream, aVer, data.m_Unknown1 );
1708 ReadCond( aStream, aVer, data.m_Unknown2 );
1709 ReadCond( aStream, aVer, data.m_Unknown3 );
1710
1711 data.m_StringPtr = aStream.ReadU32();
1712
1713 ReadCond( aStream, aVer, data.m_Unknown4 );
1714
1715 data.m_Ptr1 = aStream.ReadU32();
1716 data.m_Ptr2 = aStream.ReadU32();
1717 data.m_Ptr3 = aStream.ReadU32();
1718
1719 data.m_Flags = aStream.ReadU32();
1720
1721 return block;
1722}
1723
1724
1725static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2D( FILE_STREAM& stream, FMT_VER aVer )
1726{
1727 auto block = std::make_unique<BLOCK<BLK_0x2D_FOOTPRINT_INST>>( stream.Position() );
1728
1729 auto& data = block->GetData();
1730
1731 data.m_UnknownByte1 = stream.ReadU8();
1732 data.m_Layer = stream.ReadU8();
1733 data.m_UnknownByte2 = stream.ReadU8();
1734
1735 data.m_Key = stream.ReadU32();
1736 block->SetKey( data.m_Key );
1737 data.m_Next = stream.ReadU32();
1738 block->SetNext( data.m_Next );
1739
1740 ReadCond( stream, aVer, data.m_Unknown1 );
1741
1742 ReadCond( stream, aVer, data.m_InstRef16x );
1743
1744 data.m_Unknown2 = stream.ReadU16();
1745 data.m_Unknown3 = stream.ReadU16();
1746
1747 ReadCond( stream, aVer, data.m_Unknown4 );
1748
1749 data.m_Flags = stream.ReadU32();
1750
1751 data.m_Rotation = stream.ReadU32();
1752 data.m_CoordX = stream.ReadS32();
1753 data.m_CoordY = stream.ReadS32();
1754
1755 ReadCond( stream, aVer, data.m_InstRef );
1756
1757 data.m_GraphicPtr = stream.ReadU32();
1758 data.m_FirstPadPtr = stream.ReadU32();
1759 data.m_TextPtr = stream.ReadU32();
1760
1761 data.m_AssemblyPtr = stream.ReadU32();
1762 data.m_AreasPtr = stream.ReadU32();
1763 data.m_UnknownPtr1 = stream.ReadU32();
1764 data.m_UnknownPtr2 = stream.ReadU32();
1765
1766 return block;
1767}
1768
1769
1770static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2E( FILE_STREAM& aStream, FMT_VER aVer )
1771{
1772 auto block = std::make_unique<BLOCK<BLK_0x2E_CONNECTION>>( aStream.Position() );
1773
1774 auto& data = block->GetData();
1775
1776 data.m_Type = aStream.ReadU8();
1777 data.m_T2 = aStream.ReadU16();
1778 data.m_Key = aStream.ReadU32();
1779 block->SetKey( data.m_Key );
1780 data.m_Next = aStream.ReadU32();
1781 block->SetNext( data.m_Next );
1782 data.m_NetAssignment = aStream.ReadU32();
1783 data.m_Unknown1 = aStream.ReadU32();
1784 data.m_CoordX = aStream.ReadU32();
1785 data.m_CoordY = aStream.ReadU32();
1786 data.m_Connection = aStream.ReadU32();
1787 data.m_Unknown2 = aStream.ReadU32();
1788
1789 ReadCond( aStream, aVer, data.m_Unknown3 );
1790
1791 return block;
1792}
1793
1794
1795static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2F( FILE_STREAM& aStream, FMT_VER aVer )
1796{
1797 auto block = std::make_unique<BLOCK<BLK_0x2F_UNKNOWN>>( aStream.Position() );
1798
1799 auto& data = block->GetData();
1800
1801 data.m_Type = aStream.ReadU8();
1802 data.m_T2 = aStream.ReadU16();
1803 data.m_Key = aStream.ReadU32();
1804 block->SetKey( data.m_Key );
1805
1806 ReadArrayU32( aStream, data.m_UnknownArray );
1807
1808 return block;
1809}
1810
1811
1813{
1815
1816 props.m_Key = aStream.ReadU8();
1817 props.m_Flags = aStream.ReadU8();
1818
1819 uint8_t alignment = aStream.ReadU8();
1820 switch( alignment )
1821 {
1825 case 0x1a:
1826 default:
1828 // THROW_IO_ERROR( wxString::Format( "Unknown text alignment value: %#02x", alignment ) );
1829 }
1830
1831 uint8_t reversal = aStream.ReadU8();
1832 switch( reversal )
1833 {
1837 case 0x0c:
1838 default:
1840 //THROW_IO_ERROR( wxString::Format( "Unknown text reversal value: %#02x", reversal ) );
1841 }
1842 return props;
1843}
1844
1845
1846static std::unique_ptr<BLOCK_BASE> ParseBlock_0x30_STR_WRAPPER( FILE_STREAM& aStream, FMT_VER aVer )
1847{
1848 auto block = std::make_unique<BLOCK<BLK_0x30_STR_WRAPPER>>( aStream.Position() );
1849
1850 auto& data = block->GetData();
1851
1852 data.m_Type = aStream.ReadU8();
1853 data.m_Layer = ParseLayerInfo( aStream );
1854 data.m_Key = aStream.ReadU32();
1855 block->SetKey( data.m_Key );
1856 data.m_Next = aStream.ReadU32();
1857 block->SetNext( data.m_Next );
1858
1859 ReadCond( aStream, aVer, data.m_Unknown1 );
1860 ReadCond( aStream, aVer, data.m_Unknown2 );
1861
1862 if( data.m_Font.exists( aVer ) )
1863 {
1864 data.m_Font = ParseTextProps( aStream );
1865 }
1866
1867 ReadCond( aStream, aVer, data.m_Ptr1 );
1868 ReadCond( aStream, aVer, data.m_Unknown3 );
1869
1870 data.m_StrGraphicPtr = aStream.ReadU32();
1871
1872 ReadCond( aStream, aVer, data.m_PtrGroup_17x );
1873 ReadCond( aStream, aVer, data.m_Unknown4 );
1874
1875 if( data.m_Font16x.exists( aVer ) )
1876 {
1877 data.m_Font16x = ParseTextProps( aStream );
1878 }
1879
1880 ReadCond( aStream, aVer, data.m_Ptr2 );
1881
1882 data.m_CoordsX = aStream.ReadU32();
1883 data.m_CoordsY = aStream.ReadU32();
1884
1885 data.m_Unknown5 = aStream.ReadU32();
1886 data.m_Rotation = aStream.ReadU32();
1887
1888 ReadCond( aStream, aVer, data.m_PtrGroup_16x );
1889
1890 return block;
1891}
1892
1893
1894static std::unique_ptr<BLOCK_BASE> ParseBlock_0x31_SGRAPHIC( FILE_STREAM& aStream, FMT_VER aVer )
1895{
1896 auto block = std::make_unique<BLOCK<BLK_0x31_SGRAPHIC>>( aStream.Position() );
1897
1898 auto& data = block->GetData();
1899
1900 data.m_T = aStream.ReadU8();
1901
1902 {
1903 const uint16_t layer = aStream.ReadU16();
1904
1905 switch( layer )
1906 {
1907 case 0xF001: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::BOT_TEXT; break;
1908 case 0xF101: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_TEXT; break;
1909 case 0xF609: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::BOT_PIN; break;
1910 case 0xF709: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_PIN; break;
1911 case 0xF801: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_PIN_LABEL; break;
1912 case 0xFA0D: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::BOT_REFDES; break;
1913 case 0xFB0D: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_REFDES; break;
1914 default: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::UNKNOWN; break;
1915 }
1916 }
1917
1918 data.m_Key = aStream.ReadU32();
1919 block->SetKey( data.m_Key );
1920 data.m_StrGraphicWrapperPtr = aStream.ReadU32();
1921
1922 data.m_CoordsX = aStream.ReadU32();
1923 data.m_CoordsY = aStream.ReadU32();
1924
1925 data.m_Unknown = aStream.ReadU16();
1926 data.m_Len = aStream.ReadU16();
1927
1928 ReadCond( aStream, aVer, data.m_Un2 );
1929
1930 data.m_Value = aStream.ReadStringFixed( data.m_Len, true );
1931
1932 return block;
1933}
1934
1935
1936static std::unique_ptr<BLOCK_BASE> ParseBlock_0x32_PLACED_PAD( FILE_STREAM& aStream, FMT_VER aVer )
1937{
1938 auto block = std::make_unique<BLOCK<BLK_0x32_PLACED_PAD>>( aStream.Position() );
1939
1940 auto& data = block->GetData();
1941
1942 data.m_Type = aStream.ReadU8();
1943 data.m_Layer = ParseLayerInfo( aStream );
1944 data.m_Key = aStream.ReadU32();
1945 block->SetKey( data.m_Key );
1946 data.m_Next = aStream.ReadU32();
1947 block->SetNext( data.m_Next );
1948 data.m_NetPtr = aStream.ReadU32();
1949 data.m_Flags = aStream.ReadU32();
1950
1951 ReadCond( aStream, aVer, data.m_Prev );
1952
1953 data.m_NextInFp = aStream.ReadU32();
1954 data.m_ParentFp = aStream.ReadU32();
1955 data.m_Track = aStream.ReadU32();
1956 data.m_PadPtr = aStream.ReadU32();
1957 data.m_Ptr6 = aStream.ReadU32();
1958 data.m_Ratline = aStream.ReadU32();
1959 data.m_PtrPinNumber = aStream.ReadU32();
1960 data.m_NextInCompInst = aStream.ReadU32();
1961
1962 ReadCond( aStream, aVer, data.m_Unknown2 );
1963
1964 data.m_NameText = aStream.ReadU32();
1965 data.m_Ptr11 = aStream.ReadU32();
1966
1967 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1968 {
1969 data.m_Coords[i] = aStream.ReadS32();
1970 }
1971
1972 return block;
1973}
1974
1975
1976static std::unique_ptr<BLOCK_BASE> ParseBlock_0x33_VIA( FILE_STREAM& aStream, FMT_VER aVer )
1977{
1978 auto block = std::make_unique<BLOCK<BLK_0x33_VIA>>( aStream.Position() );
1979
1980 auto& data = block->GetData();
1981
1982 aStream.Skip( 1 );
1983
1984 data.m_LayerInfo = ParseLayerInfo( aStream );
1985 data.m_Key = aStream.ReadU32();
1986 block->SetKey( data.m_Key );
1987 data.m_Next = aStream.ReadU32();
1988 block->SetNext( data.m_Next );
1989 data.m_NetPtr = aStream.ReadU32();
1990 data.m_Unknown2 = aStream.ReadU32();
1991
1992 ReadCond( aStream, aVer, data.m_Unknown3 );
1993
1994 data.m_UnknownPtr1 = aStream.ReadU32();
1995
1996 ReadCond( aStream, aVer, data.m_UnknownPtr2 );
1997
1998 data.m_CoordsX = aStream.ReadS32();
1999 data.m_CoordsY = aStream.ReadS32();
2000
2001 data.m_Connection = aStream.ReadU32();
2002 data.m_Padstack = aStream.ReadU32();
2003 data.m_UnknownPtr5 = aStream.ReadU32();
2004 data.m_UnknownPtr6 = aStream.ReadU32();
2005
2006 data.m_Unknown4 = aStream.ReadU32();
2007 data.m_Unknown5 = aStream.ReadU32();
2008
2009 for( size_t i = 0; i < data.m_BoundingBoxCoords.size(); ++i )
2010 {
2011 data.m_BoundingBoxCoords[i] = aStream.ReadS32();
2012 }
2013
2014 return block;
2015}
2016
2017
2018static std::unique_ptr<BLOCK_BASE> ParseBlock_0x34_KEEPOUT( FILE_STREAM& aStream, FMT_VER aVer )
2019{
2020 auto block = std::make_unique<BLOCK<BLK_0x34_KEEPOUT>>( aStream.Position() );
2021
2022 auto& data = block->GetData();
2023
2024 data.m_T = aStream.ReadU8();
2025 data.m_Layer = ParseLayerInfo( aStream );
2026 data.m_Key = aStream.ReadU32();
2027 block->SetKey( data.m_Key );
2028 data.m_Next = aStream.ReadU32();
2029 block->SetNext( data.m_Next );
2030 data.m_Ptr1 = aStream.ReadU32();
2031
2032 ReadCond( aStream, aVer, data.m_Unknown1 );
2033
2034 data.m_Flags = aStream.ReadU32();
2035 data.m_FirstSegmentPtr = aStream.ReadU32();
2036 data.m_Ptr3 = aStream.ReadU32();
2037 data.m_Unknown2 = aStream.ReadU32();
2038
2039 return block;
2040}
2041
2042
2043static std::unique_ptr<BLOCK_BASE> ParseBlock_0x35( FILE_STREAM& aStream, FMT_VER aVer )
2044{
2045 auto block = std::make_unique<BLOCK<BLK_0x35_FILE_REF>>( aStream.Position() );
2046
2047 auto& data = block->GetData();
2048
2049 data.m_T2 = aStream.ReadU8();
2050 data.m_T3 = aStream.ReadU16();
2051 aStream.ReadBytes( data.m_Content.data(), data.m_Content.size() );
2052
2053 return block;
2054}
2055
2056
2057static std::unique_ptr<BLOCK_BASE> ParseBlock_0x36( FILE_STREAM& aStream, FMT_VER aVer )
2058{
2059 auto block = std::make_unique<BLOCK<BLK_0x36_DEF_TABLE>>( aStream.Position() );
2060
2061 auto& data = block->GetData();
2062
2063 aStream.Skip( 1 );
2064
2065 data.m_Code = aStream.ReadU16();
2066 data.m_Key = aStream.ReadU32();
2067 block->SetKey( data.m_Key );
2068 data.m_Next = aStream.ReadU32();
2069 block->SetNext( data.m_Next );
2070
2071 ReadCond( aStream, aVer, data.m_Unknown1 );
2072
2073 data.m_NumItems = aStream.ReadU32();
2074 data.m_Count = aStream.ReadU32();
2075 data.m_LastIdx = aStream.ReadU32();
2076 data.m_Unknown2 = aStream.ReadU32();
2077
2078 ReadCond( aStream, aVer, data.m_Unknown3 );
2079
2080 if( data.m_NumItems > 1000000 )
2081 {
2082 THROW_IO_ERRORF( wxT( "Block 0x36 item count %u exceeds limit at offset %#010zx" ),
2083 data.m_NumItems,
2084 aStream.Position() );
2085 }
2086
2087 if( data.m_Count > data.m_NumItems )
2088 {
2089 THROW_IO_ERRORF( wxT( "Block 0x36 filled count %u exceeds capacity %u at offset %#010zx" ),
2090 data.m_Count,
2091 data.m_NumItems,
2092 aStream.Position() );
2093 }
2094
2095 // Each block has m_NumItems slots but only the first m_Count are populated; the rest are
2096 // zeroes. Iterate all slots to stride across them correctly, but only keep the
2097 // actual existing items.
2098 data.m_Items.reserve( data.m_Count );
2099 for( uint32_t i = 0; i < data.m_NumItems; ++i )
2100 {
2101 const bool keep = i < data.m_Count;
2102
2103 switch( data.m_Code )
2104 {
2105 case 0x02:
2106 {
2108
2109 item.m_String = aStream.ReadStringFixed( 32, true );
2110 ReadArrayU32( aStream, item.m_Xs );
2111 ReadCond( aStream, aVer, item.m_Ys );
2112 ReadCond( aStream, aVer, item.m_Zs );
2113
2114 if( keep )
2115 data.m_Items.emplace_back( std::move( item ) );
2116 break;
2117 }
2118 case 0x03:
2119 {
2121 if( aVer >= FMT_VER::V_172 )
2122 item.m_Str = aStream.ReadStringFixed( 64, true );
2123 else
2124 item.m_Str16x = aStream.ReadStringFixed( 32, true );
2125
2126 ReadCond( aStream, aVer, item.m_Unknown1 );
2127
2128 if( keep )
2129 data.m_Items.emplace_back( std::move( item ) );
2130 break;
2131 }
2132 case 0x05:
2133 {
2135
2136 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2137 ReadCond( aStream, aVer, item.m_Unknown2 );
2138
2139 if( keep )
2140 data.m_Items.emplace_back( std::move( item ) );
2141 break;
2142 }
2143 case 0x06:
2144 {
2146
2147 item.m_N = aStream.ReadU16();
2148 item.m_R = aStream.ReadU8();
2149 item.m_S = aStream.ReadU8();
2150 item.m_Unknown1 = aStream.ReadU32();
2151
2152 ReadCond( aStream, aVer, item.m_Unknown2 );
2153
2154 if( keep )
2155 data.m_Items.emplace_back( std::move( item ) );
2156 break;
2157 }
2158 case 0x08:
2159 {
2161
2162 item.m_A = aStream.ReadU32();
2163 item.m_B = aStream.ReadU32();
2164 item.m_CharHeight = aStream.ReadU32();
2165 item.m_CharWidth = aStream.ReadU32();
2166
2167 ReadCond( aStream, aVer, item.m_Unknown2 );
2168
2169 item.m_CharacterSpace = aStream.ReadU32();
2170 item.m_LineSpace = aStream.ReadU32();
2171 item.m_Unknown3 = aStream.ReadU32();
2172 item.m_StrokeWidth = aStream.ReadU32();
2173
2174 ReadCond( aStream, aVer, item.m_Ys );
2175
2176 if( keep )
2177 data.m_Items.emplace_back( std::move( item ) );
2178 break;
2179 }
2180 case 0x0B:
2181 {
2183 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2184 if( keep )
2185 data.m_Items.emplace_back( std::move( item ) );
2186 break;
2187 }
2188 case 0x0C:
2189 {
2191 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2192 if( keep )
2193 data.m_Items.emplace_back( std::move( item ) );
2194 break;
2195 }
2196 case 0x0D:
2197 {
2199 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2200 if( keep )
2201 data.m_Items.emplace_back( std::move( item ) );
2202 break;
2203 }
2204 case 0x0F:
2205 {
2207 item.m_Key = aStream.ReadU32();
2208 ReadArrayU32( aStream, item.m_Ptrs );
2209 item.m_Ptr2 = aStream.ReadU32();
2210
2211 if( keep )
2212 data.m_Items.emplace_back( std::move( item ) );
2213
2214 break;
2215 }
2216 case 0x10:
2217 {
2219 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2220 ReadCond( aStream, aVer, item.m_Unknown2 );
2221
2222 if( keep )
2223 data.m_Items.emplace_back( std::move( item ) );
2224
2225 break;
2226 }
2227 case 0x12:
2228 {
2230 // aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2231 aStream.Skip( 1052 );
2232
2233 if( keep )
2234 data.m_Items.emplace_back( std::move( item ) );
2235
2236 break;
2237 }
2238 default: THROW_IO_ERRORF( wxT( "Unknown substruct type %#02x in block 0x36" ), data.m_Code );
2239 }
2240 }
2241
2242 return block;
2243}
2244
2245
2246static std::unique_ptr<BLOCK_BASE> ParseBlock_0x37( FILE_STREAM& aStream, FMT_VER aVer )
2247{
2248 auto block = std::make_unique<BLOCK<BLK_0x37_PTR_ARRAY>>( aStream.Position() );
2249
2250 auto& data = block->GetData();
2251
2252 data.m_T = aStream.ReadU8();
2253 data.m_T2 = aStream.ReadU16();
2254 data.m_Key = aStream.ReadU32();
2255 block->SetKey( data.m_Key );
2256 data.m_GroupPtr = aStream.ReadU32();
2257 data.m_Next = aStream.ReadU32();
2258 block->SetNext( data.m_Next );
2259 data.m_Capacity = aStream.ReadU32();
2260 data.m_Count = aStream.ReadU32();
2261 data.m_Unknown2 = aStream.ReadU32();
2262
2263 ReadCond( aStream, aVer, data.m_Unknown3 );
2264
2265 ReadArrayU32( aStream, data.m_Ptrs );
2266
2267 return block;
2268}
2269
2270
2271static std::unique_ptr<BLOCK_BASE> ParseBlock_0x38_FILM( FILE_STREAM& aStream, FMT_VER aVer )
2272{
2273 auto block = std::make_unique<BLOCK<BLK_0x38_FILM>>( aStream.Position() );
2274
2275 auto& data = block->GetData();
2276
2277 aStream.Skip( 3 );
2278
2279 data.m_Key = aStream.ReadU32();
2280 block->SetKey( data.m_Key );
2281 data.m_Next = aStream.ReadU32();
2282 block->SetNext( data.m_Next );
2283 data.m_LayerList = aStream.ReadU32();
2284
2285 if( data.m_FilmName.exists( aVer ) )
2286 {
2287 data.m_FilmName = aStream.ReadStringFixed( 20, true );
2288 }
2289
2290 ReadCond( aStream, aVer, data.m_LayerNameStr );
2291 ReadCond( aStream, aVer, data.m_Unknown2 );
2292
2293 for( size_t i = 0; i < data.m_UnknownArray1.size(); ++i )
2294 {
2295 data.m_UnknownArray1[i] = aStream.ReadU32();
2296 }
2297
2298 ReadCond( aStream, aVer, data.m_Unknown3 );
2299
2300 return block;
2301}
2302
2303
2304static std::unique_ptr<BLOCK_BASE> ParseBlock_0x39_FILM_LAYER_LIST( FILE_STREAM& aStream, FMT_VER aVer )
2305{
2306 auto block = std::make_unique<BLOCK<BLK_0x39_FILM_LAYER_LIST>>( aStream.Position() );
2307
2308 auto& data = block->GetData();
2309
2310 aStream.Skip( 3 );
2311
2312 data.m_Key = aStream.ReadU32();
2313 block->SetKey( data.m_Key );
2314 data.m_Parent = aStream.ReadU32();
2315 data.m_Head = aStream.ReadU32();
2316
2317 for( size_t i = 0; i < data.m_X.size(); ++i )
2318 {
2319 data.m_X[i] = aStream.ReadU16();
2320 }
2321
2322 return block;
2323}
2324
2325
2326static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3A_FILM_LIST_NODE( FILE_STREAM& aStream, FMT_VER aVer )
2327{
2328 auto block = std::make_unique<BLOCK<BLK_0x3A_FILM_LIST_NODE>>( aStream.Position() );
2329
2330 auto& data = block->GetData();
2331
2332 aStream.Skip( 1 );
2333
2334 data.m_Layer = ParseLayerInfo( aStream );
2335 data.m_Key = aStream.ReadU32();
2336 block->SetKey( data.m_Key );
2337 data.m_Next = aStream.ReadU32();
2338 block->SetNext( data.m_Next );
2339 data.m_Unknown = aStream.ReadU32();
2340
2341 ReadCond( aStream, aVer, data.m_Unknown1 );
2342
2343 return block;
2344}
2345
2346
2347static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3B( FILE_STREAM& aStream, FMT_VER aVer )
2348{
2349 auto block = std::make_unique<BLOCK<BLK_0x3B_PROPERTY>>( aStream.Position() );
2350
2351 auto& data = block->GetData();
2352
2353 data.m_T = aStream.ReadU8();
2354 data.m_SubType = aStream.ReadU16();
2355 data.m_Len = aStream.ReadU32();
2356
2357 data.m_Name = aStream.ReadStringFixed( 128, true );
2358 data.m_Type = aStream.ReadStringFixed( 32, true );
2359
2360 data.m_Unknown1 = aStream.ReadU32();
2361 data.m_Unknown2 = aStream.ReadU32();
2362
2363 ReadCond( aStream, aVer, data.m_Unknown3 );
2364
2365 data.m_Value = aStream.ReadStringFixed( data.m_Len, true );
2366
2367 return block;
2368}
2369
2370
2371static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3E( FILE_STREAM& aStream, FMT_VER aVer )
2372{
2373 auto block = std::make_unique<BLOCK<BLK_0x3E>>( aStream.Position() );
2374
2375 auto& data = block->GetData();
2376
2377 aStream.Skip( 3 );
2378
2379 data.m_Key = aStream.ReadU32();
2380 block->SetKey( data.m_Key );
2381
2382 for( uint32_t& word : data.m_Unknown )
2383 word = aStream.ReadU32();
2384
2385 return block;
2386}
2387
2388
2389static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3C( FILE_STREAM& aStream, FMT_VER aVer )
2390{
2391 auto block = std::make_unique<BLOCK<BLK_0x3C_KEY_LIST>>( aStream.Position() );
2392
2393 auto& data = block->GetData();
2394
2395 data.m_T = aStream.ReadU8();
2396 data.m_T2 = aStream.ReadU16();
2397 data.m_Key = aStream.ReadU32();
2398 block->SetKey( data.m_Key );
2399
2400 ReadCond( aStream, aVer, data.m_Unknown );
2401
2402 data.m_NumEntries = aStream.ReadU32();
2403
2404 if( data.m_NumEntries > 1000000 )
2405 {
2406 THROW_IO_ERRORF( wxT( "Block 0x3C entry count %u exceeds limit at offset %#010zx" ),
2407 data.m_NumEntries,
2408 aStream.Position() );
2409 }
2410
2411 data.m_Entries.reserve( data.m_NumEntries );
2412
2413 for( uint32_t i = 0; i < data.m_NumEntries; ++i )
2414 data.m_Entries.push_back( aStream.ReadU32() );
2415
2416 return block;
2417}
2418
2419
2420std::unique_ptr<BLOCK_BASE> ALLEGRO::BLOCK_PARSER::ParseBlock( bool& aEndOfObjectsMarker )
2421{
2422 // Read the type of the object
2423 // The file can end here without error.
2424 uint8_t type = 0x00;
2425 if( !m_stream.GetU8( type ) )
2426 {
2427 aEndOfObjectsMarker = true;
2428 return nullptr;
2429 }
2430
2431 std::unique_ptr<BLOCK_BASE> block;
2432
2433 switch( type )
2434 {
2435 case 0x01:
2436 {
2438 break;
2439 }
2440 case 0x03:
2441 {
2442 block = ParseBlock_0x03( m_stream, m_ver );
2443 break;
2444 }
2445 case 0x04:
2446 {
2448 break;
2449 }
2450 case 0x05:
2451 {
2453 break;
2454 }
2455 case 0x06:
2456 {
2457 block = ParseBlock_0x06( m_stream, m_ver );
2458 break;
2459 }
2460 case 0x07:
2461 {
2462 block = ParseBlock_0x07( m_stream, m_ver );
2463 break;
2464 }
2465 case 0x08:
2466 {
2467 block = ParseBlock_0x08( m_stream, m_ver );
2468 break;
2469 }
2470 case 0x09:
2471 {
2472 block = ParseBlock_0x09( m_stream, m_ver );
2473 break;
2474 }
2475 case 0x0A:
2476 {
2478 break;
2479 }
2480 case 0x0C:
2481 {
2482 block = ParseBlock_0x0C( m_stream, m_ver );
2483 break;
2484 }
2485 case 0x0D:
2486 {
2488 break;
2489 }
2490 case 0x0E:
2491 {
2492 block = ParseBlock_0x0E( m_stream, m_ver );
2493 break;
2494 }
2495 case 0x0F:
2496 {
2497 block = ParseBlock_0x0F( m_stream, m_ver );
2498 break;
2499 }
2500 case 0x10:
2501 {
2502 block = ParseBlock_0x10( m_stream, m_ver );
2503 break;
2504 }
2505 case 0x11:
2506 {
2507 block = ParseBlock_0x11( m_stream, m_ver );
2508 break;
2509 }
2510 case 0x12:
2511 {
2512 block = ParseBlock_0x12( m_stream, m_ver );
2513 break;
2514 }
2515 case 0x14:
2516 {
2517 block = ParseBlock_0x14( m_stream, m_ver );
2518 break;
2519 }
2520 case 0x15:
2521 case 0x16:
2522 case 0x17:
2523 {
2525 break;
2526 }
2527 case 0x1A:
2528 {
2529 block = ParseBlock_0x1A( m_stream, m_ver );
2530 break;
2531 }
2532 case 0x1B:
2533 {
2535 break;
2536 }
2537 case 0x1C:
2538 {
2540 break;
2541 }
2542 case 0x1D:
2543 {
2544 block = ParseBlock_0x1D( m_stream, m_ver );
2545 break;
2546 }
2547 case 0x1E:
2548 {
2549 block = ParseBlock_0x1E( m_stream, m_ver );
2550 break;
2551 }
2552 case 0x1F:
2553 {
2554 block = ParseBlock_0x1F( m_stream, m_ver );
2555 break;
2556 }
2557 case 0x20:
2558 {
2559 block = ParseBlock_0x20( m_stream, m_ver );
2560 break;
2561 }
2562 case 0x21:
2563 {
2564 block = ParseBlock_0x21( m_stream, m_ver );
2565 break;
2566 }
2567 case 0x22:
2568 {
2569 block = ParseBlock_0x22( m_stream, m_ver );
2570 break;
2571 }
2572 case 0x23:
2573 {
2575 break;
2576 }
2577 case 0x24:
2578 {
2580 break;
2581 }
2582 case 0x26:
2583 {
2584 block = ParseBlock_0x26( m_stream, m_ver );
2585 break;
2586 }
2587 case 0x27:
2588 {
2589 if( m_x27_end <= m_stream.Position() )
2590 {
2591 THROW_IO_ERRORF( wxT( "Current offset %#010zx is at or past the expected end of block 0x27 at %#010zx" ),
2592 m_stream.Position(), m_x27_end );
2593 }
2594
2596 break;
2597 }
2598 case 0x28:
2599 {
2601 break;
2602 }
2603 case 0x29:
2604 {
2606 break;
2607 }
2608 case 0x2A:
2609 {
2610 block = ParseBlock_0x2A( m_stream, m_ver );
2611 break;
2612 }
2613 case 0x2B:
2614 {
2615 block = ParseBlock_0x2B( m_stream, m_ver );
2616 break;
2617 }
2618 case 0x2C:
2619 {
2621 break;
2622 }
2623 case 0x2D:
2624 {
2625 block = ParseBlock_0x2D( m_stream, m_ver );
2626 break;
2627 }
2628 case 0x2E:
2629 {
2630 block = ParseBlock_0x2E( m_stream, m_ver );
2631 break;
2632 }
2633 case 0x2F:
2634 {
2635 block = ParseBlock_0x2F( m_stream, m_ver );
2636 break;
2637 }
2638 case 0x30:
2639 {
2641 break;
2642 }
2643 case 0x31:
2644 {
2646 break;
2647 }
2648 case 0x32:
2649 {
2651 break;
2652 }
2653 case 0x33:
2654 {
2656 break;
2657 }
2658 case 0x34:
2659 {
2661 break;
2662 }
2663 case 0x35:
2664 {
2665 block = ParseBlock_0x35( m_stream, m_ver );
2666 break;
2667 }
2668 case 0x36:
2669 {
2670 block = ParseBlock_0x36( m_stream, m_ver );
2671 break;
2672 }
2673 case 0x37:
2674 {
2675 block = ParseBlock_0x37( m_stream, m_ver );
2676 break;
2677 }
2678 case 0x38:
2679 {
2681 break;
2682 }
2683 case 0x39:
2684 {
2686 break;
2687 }
2688 case 0x3A:
2689 {
2691 break;
2692 }
2693 case 0x3B:
2694 {
2695 block = ParseBlock_0x3B( m_stream, m_ver );
2696 break;
2697 }
2698 case 0x3C:
2699 {
2700 block = ParseBlock_0x3C( m_stream, m_ver );
2701 break;
2702 }
2703 case 0x3E:
2704 {
2705 block = ParseBlock_0x3E( m_stream, m_ver );
2706 break;
2707 }
2708 case 0x00:
2709 {
2710 // Block type 0x00 marks the end of the objects section
2711 aEndOfObjectsMarker = true;
2712 break;
2713 }
2714 default:
2715 break;
2716 }
2717
2718 return block;
2719}
2720
2721
2723{
2724 const FMT_VER ver = aBoard.m_FmtVer;
2725
2726 if( m_progressReporter )
2727 {
2728 m_progressReporter->AdvancePhase( _( "Parsing Allegro objects" ) );
2729 // This isn't exactly the number we seem to parse, but it's very close
2730 m_progressReporter->SetMaxProgress( static_cast<int>( aBoard.m_Header->m_ObjectCount ) );
2731 }
2732
2733 BLOCK_PARSER blockParser( m_stream, ver, aBoard.m_Header->Get_0x27_End() );
2734
2735 THROTTLE refreshThrottle( std::chrono::milliseconds( 100 ) );
2736
2737 while( true )
2738 {
2739 const size_t offset = m_stream.Position();
2740
2741 // This seems to be always true and is quite useful for debugging out-of-sync objects
2742 wxASSERT_MSG( offset % 4 == 0,
2743 wxString::Format( "Allegro object at %#010zx, offset not aligned to 4 bytes", offset ) );
2744
2745 // Peek at the block type byte before ParseBlock consumes it so we
2746 // have the value available for error messages if the type is unknown
2747 // and ParseBlock returns nullptr.
2748 uint8_t blockTypeByte = 0;
2749 m_stream.GetU8( blockTypeByte );
2750 m_stream.Seek( offset );
2751
2752 bool endOfObjectsMarker = false;
2753 std::unique_ptr<BLOCK_BASE> block = blockParser.ParseBlock( endOfObjectsMarker );
2754
2755 if( endOfObjectsMarker )
2756 {
2757 if( ver >= FMT_VER::V_180 )
2758 {
2759 // V18 files can have zero-padded gaps between block groups. Skip
2760 // consecutive zero bytes and check if more blocks follow.
2761 size_t scanPos = m_stream.Position();
2762 uint8_t nextByte = 0;
2763
2764 while( m_stream.GetU8( nextByte ) && nextByte == 0x00 )
2765 scanPos = m_stream.Position();
2766
2767 if( nextByte > 0x00 && nextByte <= 0x3E )
2768 {
2769 size_t blockStart = scanPos;
2770
2771 if( blockStart % 4 != 0 )
2772 blockStart -= ( blockStart % 4 );
2773
2774 // After backward alignment the byte at blockStart may
2775 // differ from the non-zero byte we found. Verify it
2776 // still looks like a valid block type before continuing.
2777 uint8_t alignedByte = 0;
2778 m_stream.Seek( blockStart );
2779 m_stream.GetU8( alignedByte );
2780 m_stream.Seek( blockStart );
2781
2782 if( alignedByte == 0x00 || alignedByte > 0x3E )
2783 break;
2784
2785 wxLogTrace( traceAllegroParser,
2786 wxString::Format( "V18 zero gap from %#010zx to %#010zx, "
2787 "continuing at block type %#04x",
2788 offset, blockStart, nextByte ) );
2789 continue;
2790 }
2791 }
2792
2793 if( wxLog::IsAllowedTraceMask( traceAllegroParser ) )
2794 {
2795 wxLogTrace( traceAllegroParser,
2796 wxString::Format( "End of objects marker (0x00) at index %zu, offset %#010zx",
2797 aBoard.GetObjectCount(), offset ) );
2798 }
2799
2800 break;
2801 }
2802
2803 if( !block )
2804 {
2805 if( !m_endAtUnknownBlock )
2806 {
2807 THROW_IO_ERRORF( wxT( "Do not have parser for block index %zu type %#02x available at offset %#010zx" ),
2808 aBoard.GetObjectCount() + 1,
2809 blockTypeByte,
2810 offset );
2811 }
2812 else
2813 {
2814 wxLogTrace( traceAllegroParser,
2815 wxString::Format( "Ending at unknown block, index %zu type %#04x at offset %#010zx",
2816 aBoard.GetObjectCount(), blockTypeByte, offset ) );
2817
2818 wxFAIL_MSG( "Failed to create block" );
2819 return;
2820 }
2821 }
2822 else
2823 {
2824 wxLogTrace( traceAllegroParserBlocks,
2825 wxString::Format( "Added block %zu, type %#04x from %#010zx to %#010zx",
2826 aBoard.GetObjectCount(), block->GetBlockType(), offset,
2827 m_stream.Position() ) );
2828
2829 aBoard.InsertBlock( std::move( block ) );
2830
2831 if( m_progressReporter )
2832 {
2833 m_progressReporter->AdvanceProgress();
2834
2835 if( ( aBoard.GetObjectCount() & 0x3F ) == 0 && refreshThrottle.Ready() )
2836 m_progressReporter->KeepRefreshing();
2837 }
2838 }
2839 }
2840}
2841
2842
2843template <typename T>
2844void dumpLL( const char* name, const T& aLL )
2845{
2846 if constexpr( std::is_same_v<T, FILE_HEADER::LINKED_LIST> )
2847 {
2848 wxLogTrace( traceAllegroParser, " LL %-20s head=%#010x tail=%#010x", name, aLL.m_Head, aLL.m_Tail );
2849 }
2850 else if constexpr( VERSIONED_COND_FIELD<T> && std::is_same_v<typename T::value_type, FILE_HEADER::LINKED_LIST> )
2851 {
2852 if( aLL.has_value() )
2853 dumpLL( name, aLL.value() );
2854 }
2855}
2856
2857
2858std::unique_ptr<BRD_DB> ALLEGRO::PARSER::Parse()
2859{
2860 std::unique_ptr<BRD_DB> board = std::make_unique<BRD_DB>();
2861
2862 if( m_progressReporter )
2863 {
2864 m_progressReporter->AddPhases( 2 );
2865 m_progressReporter->AdvancePhase( "Reading file header" );
2866 }
2867
2868 PROF_TIMER parseTimer;
2869 HEADER_PARSER headerParser( m_stream );
2870
2871 try
2872 {
2873 board->m_Header = headerParser.ParseHeader();
2874
2875 if( !board->m_Header )
2876 THROW_IO_ERROR( wxT( "Failed to parse file header" ) );
2877
2878 board->m_FmtVer = headerParser.GetFormatVersion();
2879
2880 {
2881 wxLogTrace( traceAllegroParser, "Header linked lists (ver=%#010x):", board->m_Header->m_Magic );
2882
2883 dumpLL( "V18_1", board->m_Header->m_LL_V18_1 );
2884 dumpLL( "V18_2", board->m_Header->m_LL_V18_2 );
2885 dumpLL( "V18_3", board->m_Header->m_LL_V18_3 );
2886 dumpLL( "V18_4", board->m_Header->m_LL_V18_4 );
2887 dumpLL( "V18_5", board->m_Header->m_LL_V18_5 );
2888
2889 dumpLL( "0x04", board->m_Header->m_LL_0x04 );
2890 dumpLL( "0x06", board->m_Header->m_LL_0x06 );
2891 dumpLL( "0x0C", board->m_Header->m_LL_0x0C );
2892 dumpLL( "Shapes", board->m_Header->m_LL_Shapes );
2893 dumpLL( "0x14", board->m_Header->m_LL_0x14 );
2894 dumpLL( "0x1B_Nets", board->m_Header->m_LL_0x1B_Nets );
2895 dumpLL( "0x1C", board->m_Header->m_LL_0x1C );
2896 dumpLL( "0x24_0x28", board->m_Header->m_LL_0x24_0x28 );
2897 dumpLL( "Unknown1", board->m_Header->m_LL_Unknown1 );
2898 dumpLL( "0x2B", board->m_Header->m_LL_0x2B );
2899 dumpLL( "0x03_0x30", board->m_Header->m_LL_0x03_0x30 );
2900 dumpLL( "0x0A", board->m_Header->m_LL_0x0A );
2901 dumpLL( "0x1D_0x1E_0x1F", board->m_Header->m_LL_0x1D_0x1E_0x1F );
2902 dumpLL( "Unknown2", board->m_Header->m_LL_Unknown2 );
2903 dumpLL( "0x38", board->m_Header->m_LL_0x38 );
2904 dumpLL( "0x2C", board->m_Header->m_LL_0x2C );
2905 dumpLL( "0x0C_2", board->m_Header->m_LL_0x0C_2 );
2906 dumpLL( "Unknown3", board->m_Header->m_LL_Unknown3 );
2907 dumpLL( "Unknown5", board->m_Header->m_LL_Unknown5_preV18 );
2908 dumpLL( "Unknown5", board->m_Header->m_LL_Unknown5_V18 );
2909 dumpLL( "0x36", board->m_Header->m_LL_0x36 );
2910 dumpLL( "Unknown6", board->m_Header->m_LL_Unknown6 );
2911 dumpLL( "0x0A_2", board->m_Header->m_LL_0x0A_2 );
2912
2913 dumpLL( "V18_6", board->m_Header->m_LL_V18_6 );
2914 }
2915 }
2916 catch( const IO_ERROR& e )
2917 {
2918 wxString s;
2919 s += wxString::Format( "Error parsing Allegro file: %s\n", e.What() );
2920 s += wxString::Format( "Stream position: %#010lx\n", m_stream.Position() );
2921
2922 if( board->m_Header )
2923 s += wxString::Format( "File magic: %#010x\n", board->m_Header->m_Magic );
2924 else
2925 s += wxString::Format( "File magic: Unknown\n" );
2926
2927 THROW_IO_ERROR( s );
2928 }
2929
2930 wxLogTrace( traceAllegroPerf, wxT( " ReadHeader: %.3f ms" ), parseTimer.msecs( true ) ); //format:allow
2931
2932 if( board->m_FmtVer == FMT_VER::V_PRE_V16 )
2933 {
2934 wxString verStr( board->m_Header->m_AllegroVersion.data(), 60 );
2935 verStr.Trim();
2936
2937 THROW_IO_ERRORF( _( "This file was created with %s, which uses a binary format that predates Allegro 16.0 "
2938 "and is not supported by this importer.\n\n"
2939 "To import this design, open it in Cadence Allegro PCB Editor version 16.0 or later "
2940 "and re-save, then import the resulting file." ), verStr );
2941 }
2942
2943 const uint32_t stringsCount = board->m_Header->GetStringsCount();
2944 board->ReserveCapacity( board->m_Header->m_ObjectCount, stringsCount, m_stream.Size() );
2945
2946 try
2947 {
2948 ReadStringMap( m_stream, *board, stringsCount );
2949
2950 wxLogTrace( traceAllegroPerf, wxT( " ReadStringMap (%u strings): %.3f ms" ), //format:allow
2951 stringsCount, parseTimer.msecs( true ) );
2952
2953 readObjects( *board );
2954
2955 wxLogTrace( traceAllegroPerf, wxT( " readObjects (%zu objects): %.3f ms" ), //format:allow
2956 board->GetObjectCount(), parseTimer.msecs( true ) );
2957 }
2958 catch( const IO_ERROR& e )
2959 {
2960 wxString s;
2961 s += wxString::Format( "Error parsing Allegro file: %s\n", e.What() );
2962 s += wxString::Format( "Stream position: %#010lx\n", m_stream.Position() );
2963
2964 if( board->m_Header )
2965 s += wxString::Format( "File magic: %#010x\n", board->m_Header->m_Magic );
2966 else
2967 s += wxString::Format( "File magic: Unknown\n" );
2968
2969 THROW_IO_ERROR( s );
2970 }
2971
2972 // Now the object are read, collect sentinel keys
2973 board->ResolveAndValidate();
2974
2975 wxLogTrace( traceAllegroPerf, wxT( " ResolveAndValidate: %.3f ms" ), parseTimer.msecs( true ) ); //format:allow
2976 wxLogTrace( traceAllegroPerf, wxT( " Phase 1 total: %.3f ms" ), parseTimer.msecs() ); //format:allow
2977
2978 return board;
2979}
const char * name
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x35(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x36(FILE_STREAM &aStream, FMT_VER aVer)
void dumpLL(const char *name, const T &aLL)
static FILE_HEADER::LINKED_LIST ReadLL(FILE_STREAM &aStream, FMT_VER aVer)
static PAD_TYPE decodePadType(uint8_t aVal)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x04_NET_ASSIGNMENT(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x2C_TABLE(FILE_STREAM &aStream, FMT_VER aVer)
static void ReadStringMap(FILE_STREAM &stream, BRD_DB &aDb, uint32_t count)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x1F(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x3A_FILM_LIST_NODE(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x3C(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x14(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x08(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x10(FILE_STREAM &stream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x1B_NET(FILE_STREAM &stream, FMT_VER aVer)
static const wxChar *const traceAllegroParserBlocks
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x0F(FILE_STREAM &stream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x05_TRACK(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x1D(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x1C_PADSTACK(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x34_KEEPOUT(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x01_ARC(FILE_STREAM &aStream, FMT_VER aVer)
static BLK_0x30_STR_WRAPPER::TEXT_PROPERTIES ParseTextProps(FILE_STREAM &aStream)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x0D_PAD(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x1E(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x20(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x0A_DRC(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x06(FILE_STREAM &stream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x0E(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x1A(FILE_STREAM &aStream, FMT_VER aVer)
static void ReadArrayU32(FILE_STREAM &aStream, ARRAY &aArray)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x39_FILM_LAYER_LIST(FILE_STREAM &aStream, FMT_VER aVer)
static void ReadCond(FILE_STREAM &aStream, FMT_VER aFmtVer, COND_T &aField)
Read a single conditional field from the stream, if it exists at the current version.
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x09(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x38_FILM(FILE_STREAM &aStream, FMT_VER aVer)
static double ReadAllegroFloat(FILE_STREAM &aStream)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x24_RECT(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x2E(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x03(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x12(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x15_16_17_SEGMENT(FILE_STREAM &aStream, FMT_VER aVer, uint8_t aType)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x31_SGRAPHIC(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x22(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x27(FILE_STREAM &aStream, FMT_VER aVer, size_t aEndOff)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x2A(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x2F(FILE_STREAM &aStream, FMT_VER aVer)
static LAYER_INFO ParseLayerInfo(FILE_STREAM &aStream)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x07(FILE_STREAM &stream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x33_VIA(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x32_PLACED_PAD(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x37(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x2B(FILE_STREAM &stream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x2D(FILE_STREAM &stream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x21(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x23_RATLINE(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x28_SHAPE(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x11(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x26(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x3B(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x0C(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x29_PIN(FILE_STREAM &aStream, FMT_VER aVer)
static T ReadField(FILE_STREAM &aStream, FMT_VER aFmtVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x3E(FILE_STREAM &aStream, FMT_VER aVer)
static std::unique_ptr< BLOCK_BASE > ParseBlock_0x30_STR_WRAPPER(FILE_STREAM &aStream, FMT_VER aVer)
The block parser is responsible for parsing individual blocks of data from the file stream.
std::unique_ptr< BLOCK_BASE > ParseBlock(bool &aEndOfObjectsMarker)
Parse one block from the stream, returning a BLOCK_BASE representing the raw data of the block.
const size_t m_x27_end
To parse an 0x27 block, we need to know where the end of the block is in the stream.
An Allegro board database representing the contents of a .brd (and presumably .dra) file.
Definition allegro_db.h:43
std::unique_ptr< FILE_HEADER > m_Header
Definition allegro_db.h:102
size_t GetObjectCount() const
Definition allegro_db.h:52
void InsertBlock(std::unique_ptr< BLOCK_BASE > aBlock)
void AddString(uint32_t aKey, wxString &&aStr)
Definition allegro_db.h:47
Stream that reads primitive types from a memory buffer containing Allegro .brd (or ....
void ReadBytes(void *aDest, size_t aSize)
Read a number of bytes from the stream into the destination buffer.
void Skip(size_t aBytes)
size_t Position() const
std::string ReadString(bool aRoundToNextU32)
void Seek(size_t aPos)
std::string ReadStringFixed(size_t aLen, bool aRoundToNextU32)
Parses a .brd header, taking care of any version-specific differences.
std::unique_ptr< FILE_HEADER > ParseHeader()
FMT_VER GetFormatVersion() const
Get the parsed format version.
static FMT_VER FormatFromMagic(uint32_t aMagic)
Determine the format version from the magic number.
PROGRESS_REPORTER * m_progressReporter
void readObjects(BRD_DB &aDb)
FILE_STREAM & m_stream
std::unique_ptr< BRD_DB > Parse()
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
A small class to help profiling.
Definition profile.h:46
double msecs(bool aSinceLast=false)
Definition profile.h:148
Rate-limiter that fires at most once per interval.
Definition throttle.h:31
bool Ready()
Definition throttle.h:44
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
static const wxChar *const traceAllegroParser
Flag to enable debug output of Allegro parsing.
PAD_TYPE
The type of the padstack.
FMT_VER
The format of an Allegro file.
static const wxChar *const traceAllegroPerf
std::array< uint32_t, 20 > m_Entries
COND_GE< FMT_VER::V_165, uint32_t > m_Unknown_4
COND_GE< FMT_VER::V_180, std::array< uint32_t, 8 > > m_UnknownArr_v180
uint8_t m_Flags
Mask of PAD_FLAGS values.
std::string m_Name
uint32_t m_Properties
Same layer flags as REF_ENTRY, stored after the 32 byte name.
uint32_t m_Properties
uint32_t m_Unknown
uint32_t mLayerNameId
COND_GE< FMT_VER::V_172, std::array< uint32_t, 8 > > m_Ys
COND_GE_LT< FMT_VER::V_174, FMT_VER::V_190, uint32_t > m_Unknown2
COND_GE< FMT_VER::V_172, std::array< uint32_t, 2 > > m_Zs
COND_GE< FMT_VER::V_164, std::array< uint32_t, 3 > > m_Ys
COND_GE< FMT_VER::V_172, std::string > m_Str
COND_GE< FMT_VER::V_174, uint32_t > m_Unknown1
COND_LT< FMT_VER::V_172, std::string > m_Str16x
std::array< uint8_t, 28 > m_Unknown
COND_GE< FMT_VER::V_175, uint32_t > m_Unknown2
COND_LT< FMT_VER::V_172, std::array< uint32_t, 50 > > m_Unknown2
std::array< uint8_t, 1016 > m_Unknown
std::array< uint8_t, 232 > m_Unknown
std::array< uint8_t, 200 > m_Unknown
std::array< uint8_t, 108 > m_Unknown
COND_GE< FMT_VER::V_180, uint32_t > m_Unknown2
This is apparently some kind of linked list that chains though subsets objects in the file.
Substruct in a padstack object.
A type that is always false.
KIBIS_COMPONENT * comp
wxString result
Test unit parsing edge cases and error handling.