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