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