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