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, you may find one here:
19 * http://www.gnu.org/licenses/gpl-3.0.html
20 * or you may search the http://www.gnu.org website for the version 3 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
26
27#include <array>
28#include <cstring>
29
30#include <wx/sstream.h>
31#include <wx/log.h>
32#include <wx/translation.h>
33
34#include <core/profile.h>
35#include <core/throttle.h>
36#include <core/type_helpers.h>
37#include <ki_exception.h>
38
39using namespace ALLEGRO;
40
41
49static const wxChar* const traceAllegroParser = wxT( "KICAD_ALLEGRO_PARSER" );
50static const wxChar* const traceAllegroParserBlocks = wxT( "KICAD_ALLEGRO_PARSER_BLOCKS" );
51static const wxChar* const traceAllegroPerf = wxT( "KICAD_ALLEGRO_PERF" );
52
53
55{
56 uint32_t w1 = aStream.ReadU32();
57 uint32_t w2 = aStream.ReadU32();
58
59 if( aVer >= FMT_VER::V_180 )
60 {
61 // V18 stores head (chain start key) first, tail (sentinel key) second
63 .m_Tail = w2,
64 .m_Head = w1,
65 };
66 }
67
68 // V16/V17 stores tail (sentinel pointer) first, head (chain start) second
70 .m_Tail = w1,
71 .m_Head = w2,
72 };
73}
74
75
76static double ReadAllegroFloat( FILE_STREAM& aStream )
77{
78 const uint32_t a = aStream.ReadU32();
79 const uint32_t b = aStream.ReadU32();
80
81 // Combine into a 64-bit integer
82 const uint64_t combined = ( static_cast<uint64_t>( a ) << 32 ) + b;
83
84 // Copy the bits into a double
85 double result = 0;
86 std::memcpy( &result, &combined, sizeof( result ) );
87 return result;
88}
89
90
91template <typename ARRAY>
92static void ReadArrayU32( FILE_STREAM& aStream, ARRAY& aArray )
93{
94 for( size_t i = 0; i < aArray.size(); i++ )
95 {
96 aArray[i] = aStream.ReadU32();
97 }
98}
99
100
101template <typename T>
102static T ReadField( FILE_STREAM& aStream, FMT_VER aFmtVer )
103{
104 T field;
105 if constexpr( std::is_same_v<T, uint32_t> )
106 {
107 field = aStream.ReadU32();
108 }
109 else if constexpr( std::is_same_v<T, uint8_t> )
110 {
111 field = aStream.ReadU8();
112 }
113 else if constexpr( std::is_same_v<T, uint16_t> )
114 {
115 field = aStream.ReadU16();
116 }
117 else if constexpr( std::is_same_v<T, int16_t> )
118 {
119 field = aStream.ReadS16();
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( aField.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_ERROR( wxString::Format( "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_ERROR( wxString::Format( "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, DB& aDb, uint32_t count )
328{
330
331 for( uint32_t i = 0; i < count; ++i )
332 {
333 uint32_t id = stream.ReadU32();
334 wxString str = stream.ReadString( true );
335
336 aDb.AddString( id, std::move( str ) );
337 }
338}
339
340
342{
343 uint8_t classCode = aStream.ReadU8();
344 uint8_t subclassCode = aStream.ReadU8();
345
346 // Don't try to be clever and assign enums here - there are loads of them,
347 // and we don't have a perfect map yet.
348 return LAYER_INFO{
349 .m_Class = classCode,
350 .m_Subclass = subclassCode,
351 };
352}
353
354
355static std::unique_ptr<BLOCK_BASE> ParseBlock_0x01_ARC( FILE_STREAM& aStream, FMT_VER aVer )
356{
357 auto block = std::make_unique<BLOCK<BLK_0x01_ARC>>( 0x01, aStream.Position() );
358
359 auto& data = block->GetData();
360
361 aStream.Skip( 1 );
362
363 data.m_UnknownByte = aStream.ReadU8();
364 data.m_SubType = aStream.ReadU8();
365 data.m_Key = aStream.ReadU32();
366 data.m_Next = aStream.ReadU32();
367 data.m_Parent = aStream.ReadU32();
368 data.m_Unknown1 = aStream.ReadU32();
369
370 ReadCond( aStream, aVer, data.m_Unknown6 );
371
372 data.m_Width = aStream.ReadU32();
373
374 data.m_StartX = aStream.ReadS32();
375 data.m_StartY = aStream.ReadS32();
376 data.m_EndX = aStream.ReadS32();
377 data.m_EndY = aStream.ReadS32();
378
379 data.m_CenterX = ReadAllegroFloat( aStream );
380 data.m_CenterY = ReadAllegroFloat( aStream );
381 data.m_Radius = ReadAllegroFloat( aStream );
382
383 for( size_t i = 0; i < data.m_BoundingBoxCoords.size(); ++i )
384 {
385 data.m_BoundingBoxCoords[i] = aStream.ReadS32();
386 }
387
388 return block;
389}
390
391
392static std::unique_ptr<BLOCK_BASE> ParseBlock_0x03( FILE_STREAM& aStream, FMT_VER aVer )
393{
394 auto block = std::make_unique<BLOCK<BLK_0x03_FIELD>>( 0x03, aStream.Position() );
395
396 auto& data = block->GetData();
397
398 aStream.Skip( 1 );
399
400 data.m_Hdr1 = aStream.ReadU16();
401 data.m_Key = aStream.ReadU32();
402 data.m_Next = aStream.ReadU32();
403
404 ReadCond( aStream, aVer, data.m_Unknown1 );
405
406 data.m_SubType = aStream.ReadU8();
407 data.m_Hdr2 = aStream.ReadU8();
408 data.m_Size = aStream.ReadU16();
409
410 ReadCond( aStream, aVer, data.m_Unknown2 );
411
412 wxLogTrace( traceAllegroParserBlocks, wxT( " Parsed block 0x03: subtype %#02x, size %d" ), data.m_SubType,
413 data.m_Size );
414
415 switch( data.m_SubType )
416 {
417 case 0x65:
418 // Nothing for this one?
419 break;
420 case 0x64:
421 case 0x66:
422 case 0x67:
423 case 0x6A:
424 {
425 data.m_Substruct = aStream.ReadU32();
426 break;
427 }
428 case 0x69:
429 {
430 data.m_Substruct = std::array<uint32_t, 2>{
431 aStream.ReadU32(),
432 aStream.ReadU32(),
433 };
434 break;
435 }
436 case 0x68:
437 case 0x6B:
438 case 0x6D:
439 case 0x6E:
440 case 0x6F:
441 case 0x71:
442 case 0x73:
443 case 0x78:
444 {
445 data.m_Substruct = aStream.ReadStringFixed( data.m_Size, true );
446 break;
447 }
448 case 0x6C:
449 {
451 sub.m_NumEntries = aStream.ReadU32();
452
453 if( sub.m_NumEntries > 1000000 )
454 {
455 THROW_IO_ERROR( wxString::Format(
456 "Block 0x03 subtype 0x6C entry count %u exceeds limit at offset %#010zx",
457 sub.m_NumEntries, aStream.Position() ) );
458 }
459
460 sub.m_Entries.reserve( sub.m_NumEntries );
461 for( uint32_t i = 0; i < sub.m_NumEntries; ++i )
462 {
463 sub.m_Entries.push_back( aStream.ReadU32() );
464 }
465
466 data.m_Substruct = std::move( sub );
467 break;
468 }
469 case 0x70:
470 case 0x74:
471 {
473
474 sub.m_X0 = aStream.ReadU16();
475 sub.m_X1 = aStream.ReadU16();
476
477 const size_t numEntries = ( sub.m_X1 + 4 * sub.m_X0 );
478 sub.m_Entries.reserve( numEntries );
479 for( size_t i = 0; i < numEntries; ++i )
480 {
481 sub.m_Entries.push_back( aStream.ReadU8() );
482 }
483 data.m_Substruct = std::move( sub );
484 break;
485 }
486 case 0xF6:
487 {
489 for( size_t i = 0; i < sub.m_Entries.size(); ++i )
490 {
491 sub.m_Entries[i] = aStream.ReadU32();
492 }
493 data.m_Substruct = std::move( sub );
494 break;
495 }
496 default:
497 {
498 if( data.m_Size == 4 )
499 {
500 data.m_Substruct = aStream.ReadU32();
501 }
502 else if( data.m_Size == 8 )
503 {
504 std::array<uint32_t, 2> sub;
505 sub[0] = aStream.ReadU32();
506 sub[1] = aStream.ReadU32();
507 data.m_Substruct = std::move( sub );
508 }
509 else
510 {
512 wxString::Format( "Unknown substruct type %#02x with size %d", data.m_SubType, data.m_Size ) );
513 }
514 break;
515 }
516 }
517
518 return block;
519}
520
521
522static std::unique_ptr<BLOCK_BASE> ParseBlock_0x04_NET_ASSIGNMENT( FILE_STREAM& aStream, FMT_VER aVer )
523{
524 auto block = std::make_unique<BLOCK<BLK_0x04_NET_ASSIGNMENT>>( 0x04, aStream.Position() );
525
526 auto& data = block->GetData();
527
528 data.m_Type = aStream.ReadU8();
529 data.m_R = aStream.ReadU16();
530 data.m_Key = aStream.ReadU32();
531 data.m_Next = aStream.ReadU32();
532 data.m_Net = aStream.ReadU32();
533 data.m_ConnItem = aStream.ReadU32();
534
535 ReadCond( aStream, aVer, data.m_Unknown );
536
537 return block;
538}
539
540
541static std::unique_ptr<BLOCK_BASE> ParseBlock_0x05_TRACK( FILE_STREAM& aStream, FMT_VER aVer )
542{
543 auto block = std::make_unique<BLOCK<BLK_0x05_TRACK>>( 0x05, aStream.Position() );
544
545 auto& data = block->GetData();
546
547 aStream.Skip( 1 );
548
549 data.m_Layer = ParseLayerInfo( aStream );
550 data.m_Key = aStream.ReadU32();
551 data.m_Next = aStream.ReadU32();
552 data.m_NetAssignment = aStream.ReadU32();
553 data.m_UnknownPtr1 = aStream.ReadU32();
554 data.m_Unknown2 = aStream.ReadU32();
555 data.m_Unknown3 = aStream.ReadU32();
556 data.m_UnknownPtr2a = aStream.ReadU32();
557 data.m_UnknownPtr2b = aStream.ReadU32();
558 data.m_Unknown4 = aStream.ReadU32();
559 data.m_UnknownPtr3a = aStream.ReadU32();
560 data.m_UnknownPtr3b = aStream.ReadU32();
561
562 ReadCond( aStream, aVer, data.m_Unknown5a );
563 ReadCond( aStream, aVer, data.m_Unknown5b );
564
565 data.m_FirstSegPtr = aStream.ReadU32();
566 data.m_UnknownPtr5 = aStream.ReadU32();
567 data.m_Unknown6 = aStream.ReadU32();
568
569 return block;
570}
571
572
573static std::unique_ptr<BLOCK_BASE> ParseBlock_0x06( FILE_STREAM& stream, FMT_VER aVer )
574{
575 auto block = std::make_unique<BLOCK<BLK_0x06_COMPONENT>>( 0x06, stream.Position() );
576
577 auto& data = block->GetData();
578
579 stream.Skip( 3 );
580
581 data.m_Key = stream.ReadU32();
582 data.m_Next = stream.ReadU32();
583 data.m_CompDeviceType = stream.ReadU32();
584 data.m_SymbolName = stream.ReadU32();
585 data.m_FirstInstPtr = stream.ReadU32();
586 data.m_PtrFunctionSlot = stream.ReadU32();
587 data.m_PtrPinNumber = stream.ReadU32();
588 data.m_Fields = stream.ReadU32();
589
590 ReadCond( stream, aVer, data.m_Unknown1 );
591
592 return block;
593}
594
595
596static std::unique_ptr<BLOCK_BASE> ParseBlock_0x07( FILE_STREAM& stream, FMT_VER aVer )
597{
598 auto block = std::make_unique<BLOCK<BLK_0x07_COMPONENT_INST>>( 0x07, stream.Position() );
599
600 auto& data = block->GetData();
601
602 stream.Skip( 3 );
603
604 data.m_Key = stream.ReadU32();
605 data.m_Next = stream.ReadU32();
606
607 ReadCond( stream, aVer, data.m_UnknownPtr1 );
608 ReadCond( stream, aVer, data.m_Unknown2 );
609 ReadCond( stream, aVer, data.m_Unknown3 );
610
611 data.m_FpInstPtr = stream.ReadU32();
612
613 ReadCond( stream, aVer, data.m_Unknown4 );
614
615 data.m_RefDesStrPtr = stream.ReadU32();
616 data.m_FunctionInstPtr = stream.ReadU32();
617 data.m_X03Ptr = stream.ReadU32();
618 data.m_Unknown5 = stream.ReadU32();
619 data.m_FirstPadPtr = stream.ReadU32();
620
621 return block;
622}
623
624
625static std::unique_ptr<BLOCK_BASE> ParseBlock_0x08( FILE_STREAM& aStream, FMT_VER aVer )
626{
627 auto block = std::make_unique<BLOCK<BLK_0x08_PIN_NUMBER>>( 0x08, aStream.Position() );
628
629 auto& data = block->GetData();
630
631 data.m_Type = aStream.ReadU8();
632 data.m_R = aStream.ReadU16();
633 data.m_Key = aStream.ReadU32();
634
635 ReadCond( aStream, aVer, data.m_Previous );
636 ReadCond( aStream, aVer, data.m_StrPtr16x );
637
638 data.m_Next = aStream.ReadU32();
639
640 ReadCond( aStream, aVer, data.m_StrPtr );
641
642 data.m_PinNamePtr = aStream.ReadU32();
643
644 ReadCond( aStream, aVer, data.m_Unknown1 );
645
646 data.m_Ptr4 = aStream.ReadU32();
647
648 return block;
649}
650
651
652static std::unique_ptr<BLOCK_BASE> ParseBlock_0x09( FILE_STREAM& aStream, FMT_VER aVer )
653{
654 auto block = std::make_unique<BLOCK<BLK_0x09_FILL_LINK>>( 0x09, aStream.Position() );
655
656 auto& data = block->GetData();
657
658 aStream.Skip( 3 );
659
660 data.m_Key = aStream.ReadU32();
661
662 for( size_t i = 0; i < data.m_UnknownArray.size(); ++i )
663 {
664 data.m_UnknownArray[i] = aStream.ReadU32();
665 }
666
667 ReadCond( aStream, aVer, data.m_Unknown1 );
668
669 data.m_UnknownPtr1 = aStream.ReadU32();
670 data.m_UnknownPtr2 = aStream.ReadU32();
671 data.m_Unknown2 = aStream.ReadU32();
672 data.m_UnknownPtr3 = aStream.ReadU32();
673 data.m_UnknownPtr4 = aStream.ReadU32();
674
675 ReadCond( aStream, aVer, data.m_Unknown3 );
676
677 return block;
678}
679
680
681static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0A_DRC( FILE_STREAM& aStream, FMT_VER aVer )
682{
683 auto block = std::make_unique<BLOCK<BLK_0x0A_DRC>>( 0x0A, aStream.Position() );
684
685 auto& data = block->GetData();
686
687 data.m_T = aStream.ReadU8();
688 data.m_Layer = ParseLayerInfo( aStream );
689 data.m_Key = aStream.ReadU32();
690 data.m_Next = aStream.ReadU32();
691 data.m_Unknown1 = aStream.ReadU32();
692
693 ReadCond( aStream, aVer, data.m_Unknown2 );
694
695 for( size_t i = 0; i < data.m_Coords.size(); ++i )
696 {
697 data.m_Coords[i] = aStream.ReadS32();
698 }
699
700 ReadArrayU32( aStream, data.m_Unknown4 );
701 ReadArrayU32( aStream, data.m_Unknown5 );
702
703 ReadCond( aStream, aVer, data.m_Unknown6 );
704
705 return block;
706}
707
708
709static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0C( FILE_STREAM& aStream, FMT_VER aVer )
710{
711 auto block = std::make_unique<BLOCK<BLK_0x0C_PIN_DEF>>( 0x0C, aStream.Position() );
712
713 auto& data = block->GetData();
714
715 data.m_T = aStream.ReadU8();
716 data.m_Layer = ParseLayerInfo( aStream );
717
718 data.m_Key = aStream.ReadU32();
719 data.m_Next = aStream.ReadU32();
720
721 data.m_Unknown1 = aStream.ReadU32();
722 data.m_Unknown2 = aStream.ReadU32();
723
724 // Older packed format
725 ReadCond( aStream, aVer, data.m_Shape );
726 ReadCond( aStream, aVer, data.m_DrillChar );
727 ReadCond( aStream, aVer, data.m_UnknownPadding );
728
729 // V17.2+
730 ReadCond( aStream, aVer, data.m_Shape16x );
731 ReadCond( aStream, aVer, data.m_DrillChars );
732 ReadCond( aStream, aVer, data.m_Unknown_16x );
733
734 data.m_Unknown4 = aStream.ReadU32();
735
736 for( size_t i = 0; i < data.m_Coords.size(); ++i )
737 {
738 data.m_Coords[i] = aStream.ReadS32();
739 }
740
741 for( size_t i = 0; i < data.m_Size.size(); ++i )
742 {
743 data.m_Size[i] = aStream.ReadS32();
744 }
745
746 for( size_t i = 0; i < data.m_UnknownArray.size(); ++i )
747 {
748 data.m_UnknownArray[i] = aStream.ReadU32();
749 }
750
751 ReadCond( aStream, aVer, data.m_Unknown6 );
752
753 return block;
754}
755
756
757static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0D_PAD( FILE_STREAM& aStream, FMT_VER aVer )
758{
759 auto block = std::make_unique<BLOCK<BLK_0x0D_PAD>>( 0x0D, aStream.Position() );
760
761 auto& data = block->GetData();
762
763 aStream.Skip( 3 );
764
765 data.m_Key = aStream.ReadU32();
766 data.m_NameStrId = aStream.ReadU32();
767 data.m_Next = aStream.ReadU32();
768
769 ReadCond( aStream, aVer, data.m_Unknown1 );
770
771 data.m_CoordsX = aStream.ReadS32();
772 data.m_CoordsY = aStream.ReadS32();
773
774 data.m_PadStack = aStream.ReadU32();
775 data.m_Unknown2 = aStream.ReadU32();
776
777 ReadCond( aStream, aVer, data.m_Unknown3 );
778
779 data.m_Flags = aStream.ReadU32();
780 data.m_Rotation = aStream.ReadU32();
781
782 return block;
783}
784
785
786static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0E( FILE_STREAM& aStream, FMT_VER aVer )
787{
788 auto block = std::make_unique<BLOCK<BLK_0x0E_RECT>>( 0x0E, aStream.Position() );
789
790 auto& data = block->GetData();
791
792 data.m_T = aStream.ReadU8();
793 data.m_Layer = ParseLayerInfo( aStream );
794 data.m_Key = aStream.ReadU32();
795 data.m_Next = aStream.ReadU32();
796 data.m_FpPtr = aStream.ReadU32();
797
798 data.m_Unknown1 = aStream.ReadU32();
799 data.m_Unknown2 = aStream.ReadU32();
800 data.m_Unknown3 = aStream.ReadU32();
801
802 ReadCond( aStream, aVer, data.m_Unknown4 );
803 ReadCond( aStream, aVer, data.m_Unknown5 );
804
805 for( size_t i = 0; i < data.m_Coords.size(); ++i )
806 {
807 data.m_Coords[i] = aStream.ReadS32();
808 }
809
810 for( size_t i = 0; i < data.m_UnknownArr.size(); ++i )
811 {
812 data.m_UnknownArr[i] = aStream.ReadU32();
813 }
814
815 data.m_Rotation = aStream.ReadU32();
816
817 return block;
818}
819
820
821static std::unique_ptr<BLOCK_BASE> ParseBlock_0x0F( FILE_STREAM& stream, FMT_VER aVer )
822{
823 auto block = std::make_unique<BLOCK<BLK_0x0F_FUNCTION_SLOT>>( 0x0F, stream.Position() );
824
825 auto& data = block->GetData();
826
827 stream.Skip( 3 );
828
829 data.m_Key = stream.ReadU32();
830 data.m_SlotName = stream.ReadU32();
831 stream.ReadBytes( data.m_CompDeviceType.data(), data.m_CompDeviceType.size() );
832
833 data.m_Ptr0x06 = stream.ReadU32();
834 data.m_Ptr0x11 = stream.ReadU32();
835 data.m_Unknown1 = stream.ReadU32();
836
837 ReadCond( stream, aVer, data.m_Unknown2 );
838 ReadCond( stream, aVer, data.m_Unknown3 );
839
840 return block;
841}
842
843
844static std::unique_ptr<BLOCK_BASE> ParseBlock_0x10( FILE_STREAM& stream, FMT_VER aVer )
845{
846 auto block = std::make_unique<BLOCK<BLK_0x10_FUNCTION_INST>>( 0x10, stream.Position() );
847
848 auto& data = block->GetData();
849
850 stream.Skip( 3 );
851
852 data.m_Key = stream.ReadU32();
853
854 ReadCond( stream, aVer, data.m_Unknown1 );
855 data.m_ComponentInstPtr = stream.ReadU32();
856 ReadCond( stream, aVer, data.m_Unknown2 );
857 data.m_PtrX12 = stream.ReadU32();
858 data.m_Unknown3 = stream.ReadU32();
859 data.m_FunctionName = stream.ReadU32();
860 data.m_Slots = stream.ReadU32();
861 data.m_Fields = stream.ReadU32();
862
863 return block;
864}
865
866
867static std::unique_ptr<BLOCK_BASE> ParseBlock_0x11( FILE_STREAM& aStream, FMT_VER aVer )
868{
869 auto block = std::make_unique<BLOCK<BLK_0x11_PIN_NAME>>( 0x11, aStream.Position() );
870
871 auto& data = block->GetData();
872
873 data.m_Type = aStream.ReadU8();
874 data.m_R = aStream.ReadU16();
875 data.m_Key = aStream.ReadU32();
876 data.m_PinNameStrPtr = aStream.ReadU32();
877 data.m_Next = aStream.ReadU32();
878 data.m_PinNumberPtr = aStream.ReadU32();
879 data.m_Unknown1 = aStream.ReadU32();
880
881 ReadCond( aStream, aVer, data.m_Unknown2 );
882
883 return block;
884}
885
886
887static std::unique_ptr<BLOCK_BASE> ParseBlock_0x12( FILE_STREAM& aStream, FMT_VER aVer )
888{
889 auto block = std::make_unique<BLOCK<BLK_0x12_XREF>>( 0x12, aStream.Position() );
890
891 auto& data = block->GetData();
892
893 data.m_Type = aStream.ReadU8();
894 data.m_R = aStream.ReadU16();
895 data.m_Key = aStream.ReadU32();
896 data.m_Ptr1 = aStream.ReadU32();
897 data.m_Ptr2 = aStream.ReadU32();
898 data.m_Ptr3 = aStream.ReadU32();
899 data.m_Unknown1 = aStream.ReadU32();
900
901 ReadCond( aStream, aVer, data.m_Unknown2 );
902 ReadCond( aStream, aVer, data.m_Unknown3 );
903
904 return block;
905}
906
907
908static std::unique_ptr<BLOCK_BASE> ParseBlock_0x14( FILE_STREAM& aStream, FMT_VER aVer )
909{
910 auto block = std::make_unique<BLOCK<BLK_0x14_GRAPHIC>>( 0x14, aStream.Position() );
911
912 auto& data = block->GetData();
913
914 data.m_Type = aStream.ReadU8();
915 data.m_Layer = ParseLayerInfo( aStream );
916 data.m_Key = aStream.ReadU32();
917 data.m_Next = aStream.ReadU32();
918 data.m_Parent = aStream.ReadU32();
919 data.m_Flags = aStream.ReadU32();
920
921 ReadCond( aStream, aVer, data.m_Unknown2 );
922
923 data.m_SegmentPtr = aStream.ReadU32();
924 data.m_Ptr0x03 = aStream.ReadU32();
925 data.m_Ptr0x26 = aStream.ReadU32();
926
927 return block;
928}
929
930
931static std::unique_ptr<BLOCK_BASE> ParseBlock_0x15_16_17_SEGMENT( FILE_STREAM& aStream, FMT_VER aVer, uint8_t aType )
932{
933 auto block = std::make_unique<BLOCK<BLK_0x15_16_17_SEGMENT>>( aType, aStream.Position() );
934
935 auto& data = block->GetData();
936
937 aStream.Skip( 3 );
938
939 data.m_Key = aStream.ReadU32();
940 data.m_Next = aStream.ReadU32();
941 data.m_Parent = aStream.ReadU32();
942 data.m_Flags = aStream.ReadU32();
943
944 ReadCond( aStream, aVer, data.m_Unknown2 );
945
946 data.m_Width = aStream.ReadU32();
947
948 data.m_StartX = aStream.ReadS32();
949 data.m_StartY = aStream.ReadS32();
950 data.m_EndX = aStream.ReadS32();
951 data.m_EndY = aStream.ReadS32();
952
953 return block;
954}
955
956
957static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1B_NET( FILE_STREAM& stream, FMT_VER aVer )
958{
959 auto block = std::make_unique<BLOCK<BLK_0x1B_NET>>( 0x1B, stream.Position() );
960
961 auto& data = block->GetData();
962
963 stream.Skip( 3 );
964
965 data.m_Key = stream.ReadU32();
966 data.m_Next = stream.ReadU32();
967 data.m_NetName = stream.ReadU32();
968 data.m_Unknown1 = stream.ReadU32();
969
970 ReadCond( stream, aVer, data.m_Unknown2 );
971
972 data.m_Type = stream.ReadU32();
973 data.m_Assignment = stream.ReadU32();
974 data.m_Ratline = stream.ReadU32();
975 data.m_FieldsPtr = stream.ReadU32();
976 data.m_MatchGroupPtr = stream.ReadU32();
977 data.m_ModelPtr = stream.ReadU32();
978 data.m_UnknownPtr4 = stream.ReadU32();
979 data.m_UnknownPtr5 = stream.ReadU32();
980 data.m_UnknownPtr6 = stream.ReadU32();
981
982 return block;
983}
984
985
986static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1C_PADSTACK( FILE_STREAM& aStream, FMT_VER aVer )
987{
988 auto block = std::make_unique<BLOCK<BLK_0x1C_PADSTACK>>( 0x1C, aStream.Position() );
989
990 auto& data = block->GetData();
991
992 data.m_UnknownByte1 = aStream.ReadU8();
993 data.m_N = aStream.ReadU8();
994 data.m_UnknownByte2 = aStream.ReadU8();
995
996 data.m_Key = aStream.ReadU32();
997 data.m_Next = aStream.ReadU32();
998
999 data.m_PadStr = aStream.ReadU32();
1000 data.m_Drill = aStream.ReadU32();
1001 data.m_Unknown2 = aStream.ReadU32();
1002 data.m_PadPath = aStream.ReadU32();
1003
1004 ReadCond( aStream, aVer, data.m_Unknown3 );
1005 ReadCond( aStream, aVer, data.m_Unknown4 );
1006 ReadCond( aStream, aVer, data.m_Unknown5 );
1007 ReadCond( aStream, aVer, data.m_Unknown6 );
1008
1009 {
1010 const uint8_t t = aStream.ReadU8();
1011
1012 // clang-format off
1013 switch( (t & 0xF0) >> 4 )
1014 {
1015 case 0x00:
1016 data.m_Type = PAD_TYPE::THROUGH_VIA;
1017 break;
1018 case 0x01:
1019 data.m_Type = PAD_TYPE::VIA;
1020 break;
1021 case 0x02:
1022 case 0x0a: // Unclear what the difference is
1023 data.m_Type = PAD_TYPE::SMD_PIN;
1024 break;
1025 case 0x03:
1026 data.m_Type = PAD_TYPE::SLOT;
1027 break;
1028 case 0x08:
1029 data.m_Type = PAD_TYPE::NPTH;
1030 break;
1031 default:
1032 THROW_IO_ERROR( wxString::Format( "Unknown padstack type 0x%x", t ) );
1033 break;
1034 }
1035 // clang-format on
1036 data.m_A = ( t & 0x0F );
1037 }
1038
1039 data.m_B = aStream.ReadU8();
1040 data.m_Flags = aStream.ReadU8();
1041 data.m_D = aStream.ReadU8();
1042
1043 ReadCond( aStream, aVer, data.m_Unknown7 );
1044 ReadCond( aStream, aVer, data.m_Unknown8 );
1045 ReadCond( aStream, aVer, data.m_Unknown9 );
1046
1047 ReadCond( aStream, aVer, data.m_Unknown10 );
1048 data.m_LayerCount = aStream.ReadU16();
1049
1050 if( data.m_LayerCount > 256 )
1051 {
1052 THROW_IO_ERROR( wxString::Format( "Padstack layer count %u exceeds maximum at offset %#010zx",
1053 data.m_LayerCount, aStream.Position() ) );
1054 }
1055
1056 ReadCond( aStream, aVer, data.m_Unknown11 );
1057
1058 ReadArrayU32( aStream, data.m_DrillArr );
1059
1060 ReadCond( aStream, aVer, data.m_SlotAndUnknownArr );
1061 ReadCond( aStream, aVer, data.m_UnknownArr8_2 );
1062
1063 // V180 has 8 extra uint32s between the fixed arrays and the component table
1064 ReadCond( aStream, aVer, data.m_V180Trailer );
1065
1066 // Work out how many fixed slots we have, and how many per-layer slots
1067 data.m_NumFixedCompEntries = aVer < FMT_VER::V_172 ? 10 : 21;
1068 data.m_NumCompsPerLayer = aVer < FMT_VER::V_172 ? 3 : 4;
1069
1070 const size_t nComps = data.m_NumFixedCompEntries + ( data.m_LayerCount * data.m_NumCompsPerLayer );
1071
1072 data.m_Components.reserve( nComps );
1073 for( size_t i = 0; i < nComps; ++i )
1074 {
1075 PADSTACK_COMPONENT& comp = data.m_Components.emplace_back();
1076
1077 comp.m_Type = aStream.ReadU8();
1078
1079 comp.m_UnknownByte1 = aStream.ReadU8();
1080 comp.m_UnknownByte2 = aStream.ReadU8();
1081 comp.m_UnknownByte3 = aStream.ReadU8();
1082
1083 ReadCond( aStream, aVer, comp.m_Unknown1 );
1084
1085 comp.m_W = aStream.ReadS32();
1086 comp.m_H = aStream.ReadS32();
1087
1088 ReadCond( aStream, aVer, comp.m_Z1 );
1089
1090 comp.m_X3 = aStream.ReadS32();
1091 comp.m_X4 = aStream.ReadS32();
1092
1093 ReadCond( aStream, aVer, comp.m_Z );
1094
1095 comp.m_StrPtr = aStream.ReadU32();
1096
1097 // The last component has a different size only in < 17.2
1098 if( !( aVer < FMT_VER::V_172 && i == nComps - 1 ) )
1099 {
1100 comp.m_Z2 = aStream.ReadU32();
1101 }
1102 }
1103
1104 {
1105 const size_t nElems = data.m_N * ( ( aVer < FMT_VER::V_172 ) ? 8 : 10 );
1106
1107 data.m_UnknownArrN.reserve( nElems );
1108 for( size_t i = 0; i < nElems; ++i )
1109 {
1110 data.m_UnknownArrN.push_back( aStream.ReadU32() );
1111 }
1112 }
1113
1114 return block;
1115}
1116
1117
1118static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1D( FILE_STREAM& aStream, FMT_VER aVer )
1119{
1120 auto block = std::make_unique<BLOCK<BLK_0x1D_CONSTRAINT_SET>>( 0x1D, aStream.Position() );
1121
1122 auto& data = block->GetData();
1123
1124 aStream.Skip( 3 );
1125
1126 data.m_Key = aStream.ReadU32();
1127 data.m_Next = aStream.ReadU32();
1128 data.m_NameStrKey = aStream.ReadU32();
1129 data.m_FieldPtr = aStream.ReadU32();
1130
1131 data.m_SizeA = aStream.ReadU16();
1132 data.m_SizeB = aStream.ReadU16();
1133
1134 data.m_DataB.resize( data.m_SizeB );
1135
1136 for( auto& item : data.m_DataB )
1137 aStream.ReadBytes( item.data(), item.size() );
1138
1139 data.m_DataA.resize( data.m_SizeA );
1140
1141 for( auto& item : data.m_DataA )
1142 aStream.ReadBytes( item.data(), item.size() );
1143
1144 ReadCond( aStream, aVer, data.m_Unknown4 );
1145
1146 return block;
1147}
1148
1149
1150static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1E( FILE_STREAM& aStream, FMT_VER aVer )
1151{
1152 auto block = std::make_unique<BLOCK<BLK_0x1E_SI_MODEL>>( 0x1E, aStream.Position() );
1153
1154 auto& data = block->GetData();
1155
1156 data.m_Type = aStream.ReadU8();
1157 data.m_T2 = aStream.ReadU16();
1158 data.m_Key = aStream.ReadU32();
1159 data.m_Next = aStream.ReadU32();
1160
1161 ReadCond( aStream, aVer, data.m_Unknown2 );
1162 ReadCond( aStream, aVer, data.m_Unknown3 );
1163
1164 data.m_StrPtr = aStream.ReadU32();
1165 data.m_Size = aStream.ReadU32();
1166
1167 data.m_String = aStream.ReadStringFixed( data.m_Size, true );
1168
1169 ReadCond( aStream, aVer, data.m_Unknown4 );
1170
1171 return block;
1172}
1173
1174
1175static std::unique_ptr<BLOCK_BASE> ParseBlock_0x1F( FILE_STREAM& aStream, FMT_VER aVer )
1176{
1177 auto block = std::make_unique<BLOCK<BLK_0x1F_PADSTACK_DIM>>( 0x1F, aStream.Position() );
1178
1179 auto& data = block->GetData();
1180
1181 aStream.Skip( 3 );
1182
1183 data.m_Key = aStream.ReadU32();
1184
1185 data.m_Next = aStream.ReadU32();
1186 data.m_Unknown2 = aStream.ReadU32();
1187 data.m_Unknown3 = aStream.ReadU32();
1188 data.m_Unknown4 = aStream.ReadU32();
1189 data.m_Unknown5 = aStream.ReadU16();
1190
1191 data.m_Size = aStream.ReadU16();
1192
1193 size_t substructSize = 0;
1194 if( aVer >= FMT_VER::V_175 )
1195 substructSize = data.m_Size * 384 + 8;
1196 else if( aVer >= FMT_VER::V_172 )
1197 substructSize = data.m_Size * 280 + 8;
1198 else if( aVer >= FMT_VER::V_162 )
1199 substructSize = data.m_Size * 280 + 4;
1200 else
1201 substructSize = data.m_Size * 240 + 4;
1202
1203 data.m_Substruct.resize( substructSize );
1204 aStream.ReadBytes( data.m_Substruct.data(), substructSize );
1205
1206 return block;
1207}
1208
1209
1210static std::unique_ptr<BLOCK_BASE> ParseBlock_0x20( FILE_STREAM& aStream, FMT_VER aVer )
1211{
1212 auto block = std::make_unique<BLOCK<BLK_0x20_UNKNOWN>>( 0x20, aStream.Position() );
1213
1214 auto& data = block->GetData();
1215
1216 data.m_Type = aStream.ReadU8();
1217 data.m_R = aStream.ReadU16();
1218 data.m_Key = aStream.ReadU32();
1219 data.m_Next = aStream.ReadU32();
1220
1221 ReadArrayU32( aStream, data.m_UnknownArray1 );
1222 ReadCond( aStream, aVer, data.m_UnknownArray2 );
1223
1224 return block;
1225}
1226
1227
1228static std::unique_ptr<BLOCK_BASE> ParseBlock_0x21( FILE_STREAM& aStream, FMT_VER aVer )
1229{
1230 auto block = std::make_unique<BLOCK<BLK_0x21_BLOB>>( 0x21, aStream.Position() );
1231
1232 auto& data = block->GetData();
1233
1234 data.m_Type = aStream.ReadU8();
1235 data.m_R = aStream.ReadU16();
1236
1237 data.m_Size = aStream.ReadU32();
1238
1239 if( data.m_Size < 12 )
1240 {
1241 THROW_IO_ERROR( wxString::Format( "Block 0x21 size %u too small (minimum 12) at offset %#010zx",
1242 data.m_Size, aStream.Position() ) );
1243 }
1244
1245 data.m_Key = aStream.ReadU32();
1246
1247 const size_t nBytes = data.m_Size - 12;
1248 data.m_Data.resize( nBytes );
1249 aStream.ReadBytes( data.m_Data.data(), nBytes );
1250
1251 return block;
1252}
1253
1254
1255static std::unique_ptr<BLOCK_BASE> ParseBlock_0x22( FILE_STREAM& aStream, FMT_VER aVer )
1256{
1257 auto block = std::make_unique<BLOCK<BLK_0x22_UNKNOWN>>( 0x22, aStream.Position() );
1258
1259 auto& data = block->GetData();
1260
1261 data.m_Type = aStream.ReadU8();
1262 data.m_T2 = aStream.ReadU16();
1263 data.m_Key = aStream.ReadU32();
1264
1265 ReadCond( aStream, aVer, data.m_Unknown1 );
1266
1267 ReadArrayU32( aStream, data.m_UnknownArray );
1268
1269 return block;
1270}
1271
1272
1273static std::unique_ptr<BLOCK_BASE> ParseBlock_0x23_RATLINE( FILE_STREAM& aStream, FMT_VER aVer )
1274{
1275 auto block = std::make_unique<BLOCK<BLK_0x23_RATLINE>>( 0x23, aStream.Position() );
1276
1277 auto& data = block->GetData();
1278
1279 data.m_Type = aStream.ReadU8();
1280 data.m_Layer = ParseLayerInfo( aStream );
1281 data.m_Key = aStream.ReadU32();
1282 data.m_Next = aStream.ReadU32();
1283
1284 ReadArrayU32( aStream, data.m_Flags );
1285
1286 data.m_Ptr1 = aStream.ReadU32();
1287 data.m_Ptr2 = aStream.ReadU32();
1288 data.m_Ptr3 = aStream.ReadU32();
1289
1290 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1291 {
1292 data.m_Coords[i] = aStream.ReadS32();
1293 }
1294
1295 ReadArrayU32( aStream, data.m_Unknown1 );
1296
1297 ReadCond( aStream, aVer, data.m_Unknown2 );
1298 ReadCond( aStream, aVer, data.m_Unknown3 );
1299
1300 return block;
1301}
1302
1303
1304static std::unique_ptr<BLOCK_BASE> ParseBlock_0x24_RECT( FILE_STREAM& aStream, FMT_VER aVer )
1305{
1306 auto block = std::make_unique<BLOCK<BLK_0x24_RECT>>( 0x24, aStream.Position() );
1307
1308 auto& data = block->GetData();
1309
1310 data.m_Type = aStream.ReadU8();
1311 data.m_Layer = ParseLayerInfo( aStream );
1312 data.m_Key = aStream.ReadU32();
1313 data.m_Next = aStream.ReadU32();
1314 data.m_Parent = aStream.ReadU32();
1315 data.m_Unknown1 = aStream.ReadU32();
1316
1317 ReadCond( aStream, aVer, data.m_Unknown2 );
1318
1319 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1320 {
1321 data.m_Coords[i] = aStream.ReadS32();
1322 }
1323
1324 data.m_Ptr2 = aStream.ReadU32();
1325
1326 data.m_Unknown3 = aStream.ReadU32();
1327 data.m_Unknown4 = aStream.ReadU32();
1328 data.m_Rotation = aStream.ReadU32();
1329
1330 return block;
1331}
1332
1333
1334static std::unique_ptr<BLOCK_BASE> ParseBlock_0x26( FILE_STREAM& aStream, FMT_VER aVer )
1335{
1336 auto block = std::make_unique<BLOCK<BLK_0x26_MATCH_GROUP>>( 0x26, aStream.Position() );
1337
1338 auto& data = block->GetData();
1339
1340 data.m_Type = aStream.ReadU8();
1341 data.m_R = aStream.ReadU16();
1342 data.m_Key = aStream.ReadU32();
1343 data.m_MemberPtr = aStream.ReadU32();
1344
1345 ReadCond( aStream, aVer, data.m_Unknown1 );
1346
1347 data.m_GroupPtr = aStream.ReadU32();
1348 data.m_ConstPtr = aStream.ReadU32();
1349
1350 ReadCond( aStream, aVer, data.m_Unknown2 );
1351
1352 return block;
1353}
1354
1355
1356static std::unique_ptr<BLOCK_BASE> ParseBlock_0x27( FILE_STREAM& aStream, FMT_VER aVer, size_t aEndOff )
1357{
1358 auto block = std::make_unique<BLOCK<BLK_0x27_CSTRMGR_XREF>>( 0x27, aStream.Position() );
1359
1360 auto& data = block->GetData();
1361
1362 const size_t totalBytes = aEndOff - 1 - aStream.Position();
1363
1364 // The blob starts with 3 bytes of padding, then uint32 LE values
1365 constexpr size_t kPadding = 3;
1366
1367 if( totalBytes <= kPadding )
1368 {
1369 aStream.Skip( totalBytes );
1370 return block;
1371 }
1372
1373 aStream.Skip( kPadding );
1374
1375 const size_t payloadBytes = totalBytes - kPadding;
1376 const size_t numValues = payloadBytes / 4;
1377 const size_t remainder = payloadBytes % 4;
1378
1379 data.m_Refs.resize( numValues );
1380
1381 for( size_t i = 0; i < numValues; i++ )
1382 data.m_Refs[i] = aStream.ReadU32();
1383
1384 if( remainder > 0 )
1385 aStream.Skip( remainder );
1386
1387 return block;
1388}
1389
1390
1391static std::unique_ptr<BLOCK_BASE> ParseBlock_0x28_SHAPE( FILE_STREAM& aStream, FMT_VER aVer )
1392{
1393 auto block = std::make_unique<BLOCK<BLK_0x28_SHAPE>>( 0x28, aStream.Position() );
1394
1395 auto& data = block->GetData();
1396
1397 data.m_Type = aStream.ReadU8();
1398 data.m_Layer = ParseLayerInfo( aStream );
1399 data.m_Key = aStream.ReadU32();
1400 data.m_Next = aStream.ReadU32();
1401 data.m_Ptr1 = aStream.ReadU32();
1402 data.m_Unknown1 = aStream.ReadU32();
1403
1404 ReadCond( aStream, aVer, data.m_Unknown2 );
1405 ReadCond( aStream, aVer, data.m_Unknown3 );
1406
1407 data.m_Ptr2 = aStream.ReadU32();
1408 data.m_Ptr3 = aStream.ReadU32();
1409 data.m_FirstKeepoutPtr = aStream.ReadU32();
1410 data.m_FirstSegmentPtr = aStream.ReadU32();
1411 data.m_Unknown4 = aStream.ReadU32();
1412 data.m_Unknown5 = aStream.ReadU32();
1413
1414 ReadCond( aStream, aVer, data.m_TablePtr );
1415
1416 data.m_Ptr6 = aStream.ReadU32();
1417
1418 ReadCond( aStream, aVer, data.m_TablePtr_16x );
1419
1420 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1421 {
1422 data.m_Coords[i] = aStream.ReadS32();
1423 }
1424
1425 return block;
1426}
1427
1428
1429static std::unique_ptr<BLOCK_BASE> ParseBlock_0x29_PIN( FILE_STREAM& aStream, FMT_VER aVer )
1430{
1431 auto block = std::make_unique<BLOCK<BLK_0x29_PIN>>( 0x29, aStream.Position() );
1432
1433 auto& data = block->GetData();
1434
1435 data.m_Type = aStream.ReadU8();
1436 data.m_T = aStream.ReadU16();
1437 data.m_Key = aStream.ReadU32();
1438
1439 data.m_Ptr1 = aStream.ReadU32();
1440 data.m_Ptr2 = aStream.ReadU32();
1441
1442 data.m_Null = aStream.ReadU32();
1443
1444 data.m_Ptr3 = aStream.ReadU32();
1445
1446 data.m_Coord1 = aStream.ReadS32();
1447 data.m_Coord2 = aStream.ReadS32();
1448
1449 data.m_PtrPadstack = aStream.ReadU32();
1450
1451 data.m_Unknown1 = aStream.ReadU32();
1452
1453 data.m_PtrX30 = aStream.ReadU32();
1454
1455 data.m_Unknown2 = aStream.ReadU32();
1456 data.m_Unknown3 = aStream.ReadU32();
1457 data.m_Unknown4 = aStream.ReadU32();
1458
1459 return block;
1460}
1461
1462
1463static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2A( FILE_STREAM& aStream, FMT_VER aVer )
1464{
1465 auto block = std::make_unique<BLOCK<BLK_0x2A_LAYER_LIST>>( 0x2A, aStream.Position() );
1466
1467 auto& data = block->GetData();
1468
1469 aStream.Skip( 1 );
1470
1471 data.m_NumEntries = aStream.ReadU16();
1472
1473 ReadCond( aStream, aVer, data.m_Unknown );
1474
1475 if( data.m_NonRefEntries.exists( aVer ) )
1476 {
1477 data.m_NonRefEntries = std::vector<BLK_0x2A_LAYER_LIST::NONREF_ENTRY>();
1478 data.m_NonRefEntries->reserve( data.m_NumEntries );
1479 for( size_t i = 0; i < data.m_NumEntries; ++i )
1480 {
1481 BLK_0x2A_LAYER_LIST::NONREF_ENTRY& entry = data.m_NonRefEntries->emplace_back();
1482
1483 entry.m_Name = aStream.ReadStringFixed( 36, true );
1484 }
1485 }
1486 else
1487 {
1488 data.m_RefEntries = std::vector<BLK_0x2A_LAYER_LIST::REF_ENTRY>();
1489 data.m_RefEntries->reserve( data.m_NumEntries );
1490 for( size_t i = 0; i < data.m_NumEntries; ++i )
1491 {
1492 BLK_0x2A_LAYER_LIST::REF_ENTRY& entry = data.m_RefEntries->emplace_back();
1493
1494 entry.mLayerNameId = aStream.ReadU32();
1495 entry.m_Properties = aStream.ReadU32();
1496 entry.m_Unknown = aStream.ReadU32();
1497 }
1498 }
1499
1500 data.m_Key = aStream.ReadU32();
1501
1502 return block;
1503}
1504
1505
1506static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2B( FILE_STREAM& stream, FMT_VER aVer )
1507{
1508 auto block = std::make_unique<BLOCK<BLK_0x2B_FOOTPRINT_DEF>>( 0x2B, stream.Position() );
1509
1510 auto& data = block->GetData();
1511
1512 stream.Skip( 3 );
1513
1514 data.m_Key = stream.ReadU32();
1515 data.m_FpStrRef = stream.ReadU32();
1516 data.m_Unknown1 = stream.ReadU32();
1517 ReadArrayU32( stream, data.m_Coords );
1518 data.m_Next = stream.ReadU32();
1519 data.m_FirstInstPtr = stream.ReadU32();
1520 data.m_UnknownPtr3 = stream.ReadU32();
1521 data.m_UnknownPtr4 = stream.ReadU32();
1522 data.m_UnknownPtr5 = stream.ReadU32();
1523 data.m_SymLibPathPtr = stream.ReadU32();
1524 data.m_UnknownPtr6 = stream.ReadU32();
1525 data.m_UnknownPtr7 = stream.ReadU32();
1526 data.m_UnknownPtr8 = stream.ReadU32();
1527
1528 ReadCond( stream, aVer, data.m_Unknown2 );
1529 ReadCond( stream, aVer, data.m_Unknown3 );
1530
1531 return block;
1532}
1533
1534
1535static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2C_TABLE( FILE_STREAM& aStream, FMT_VER aVer )
1536{
1537 auto block = std::make_unique<BLOCK<BLK_0x2C_TABLE>>( 0x2C, aStream.Position() );
1538
1539 auto& data = block->GetData();
1540
1541 data.m_Type = aStream.ReadU8();
1542 data.m_SubType = aStream.ReadU16();
1543 data.m_Key = aStream.ReadU32();
1544 data.m_Next = aStream.ReadU32();
1545
1546 ReadCond( aStream, aVer, data.m_Unknown1 );
1547 ReadCond( aStream, aVer, data.m_Unknown2 );
1548 ReadCond( aStream, aVer, data.m_Unknown3 );
1549
1550 data.m_StringPtr = aStream.ReadU32();
1551
1552 ReadCond( aStream, aVer, data.m_Unknown4 );
1553
1554 data.m_Ptr1 = aStream.ReadU32();
1555 data.m_Ptr2 = aStream.ReadU32();
1556 data.m_Ptr3 = aStream.ReadU32();
1557
1558 data.m_Flags = aStream.ReadU32();
1559
1560 return block;
1561}
1562
1563
1564static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2D( FILE_STREAM& stream, FMT_VER aVer )
1565{
1566 auto block = std::make_unique<BLOCK<BLK_0x2D_FOOTPRINT_INST>>( 0x2D, stream.Position() );
1567
1568 auto& data = block->GetData();
1569
1570 data.m_UnknownByte1 = stream.ReadU8();
1571 data.m_Layer = stream.ReadU8();
1572 data.m_UnknownByte2 = stream.ReadU8();
1573
1574 data.m_Key = stream.ReadU32();
1575 data.m_Next = stream.ReadU32();
1576
1577 ReadCond( stream, aVer, data.m_Unknown1 );
1578
1579 ReadCond( stream, aVer, data.m_InstRef16x );
1580
1581 data.m_Unknown2 = stream.ReadU16();
1582 data.m_Unknown3 = stream.ReadU16();
1583
1584 ReadCond( stream, aVer, data.m_Unknown4 );
1585
1586 data.m_Flags = stream.ReadU32();
1587
1588 data.m_Rotation = stream.ReadU32();
1589 data.m_CoordX = stream.ReadS32();
1590 data.m_CoordY = stream.ReadS32();
1591
1592 ReadCond( stream, aVer, data.m_InstRef );
1593
1594 data.m_GraphicPtr = stream.ReadU32();
1595 data.m_FirstPadPtr = stream.ReadU32();
1596 data.m_TextPtr = stream.ReadU32();
1597
1598 data.m_AssemblyPtr = stream.ReadU32();
1599 data.m_AreasPtr = stream.ReadU32();
1600 data.m_UnknownPtr1 = stream.ReadU32();
1601 data.m_UnknownPtr2 = stream.ReadU32();
1602
1603 return block;
1604}
1605
1606
1607static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2E( FILE_STREAM& aStream, FMT_VER aVer )
1608{
1609 auto block = std::make_unique<BLOCK<BLK_0x2E_CONNECTION>>( 0x2E, aStream.Position() );
1610
1611 auto& data = block->GetData();
1612
1613 data.m_Type = aStream.ReadU8();
1614 data.m_T2 = aStream.ReadU16();
1615 data.m_Key = aStream.ReadU32();
1616 data.m_Next = aStream.ReadU32();
1617 data.m_NetAssignment = aStream.ReadU32();
1618 data.m_Unknown1 = aStream.ReadU32();
1619 data.m_CoordX = aStream.ReadU32();
1620 data.m_CoordY = aStream.ReadU32();
1621 data.m_Connection = aStream.ReadU32();
1622 data.m_Unknown2 = aStream.ReadU32();
1623
1624 ReadCond( aStream, aVer, data.m_Unknown3 );
1625
1626 return block;
1627}
1628
1629
1630static std::unique_ptr<BLOCK_BASE> ParseBlock_0x2F( FILE_STREAM& aStream, FMT_VER aVer )
1631{
1632 auto block = std::make_unique<BLOCK<BLK_0x2F_UNKNOWN>>( 0x2F, aStream.Position() );
1633
1634 auto& data = block->GetData();
1635
1636 data.m_Type = aStream.ReadU8();
1637 data.m_T2 = aStream.ReadU16();
1638 data.m_Key = aStream.ReadU32();
1639
1640 ReadArrayU32( aStream, data.m_UnknownArray );
1641
1642 return block;
1643}
1644
1645
1647{
1649
1650 props.m_Key = aStream.ReadU8();
1651 props.m_Flags = aStream.ReadU8();
1652
1653 uint8_t alignment = aStream.ReadU8();
1654 switch( alignment )
1655 {
1659 case 0x1a:
1660 default:
1662 // THROW_IO_ERROR( wxString::Format( "Unknown text alignment value: %#02x", alignment ) );
1663 }
1664
1665 uint8_t reversal = aStream.ReadU8();
1666 switch( reversal )
1667 {
1670 case 0x0c:
1671 default:
1673 //THROW_IO_ERROR( wxString::Format( "Unknown text reversal value: %#02x", reversal ) );
1674 }
1675 return props;
1676}
1677
1678
1679static std::unique_ptr<BLOCK_BASE> ParseBlock_0x30_STR_WRAPPER( FILE_STREAM& aStream, FMT_VER aVer )
1680{
1681 auto block = std::make_unique<BLOCK<BLK_0x30_STR_WRAPPER>>( 0x30, aStream.Position() );
1682
1683 auto& data = block->GetData();
1684
1685 data.m_Type = aStream.ReadU8();
1686 data.m_Layer = ParseLayerInfo( aStream );
1687 data.m_Key = aStream.ReadU32();
1688 data.m_Next = aStream.ReadU32();
1689
1690 ReadCond( aStream, aVer, data.m_Unknown1 );
1691 ReadCond( aStream, aVer, data.m_Unknown2 );
1692
1693 if( data.m_Font.exists( aVer ) )
1694 {
1695 data.m_Font = ParseTextProps( aStream );
1696 }
1697
1698 ReadCond( aStream, aVer, data.m_Ptr1 );
1699 ReadCond( aStream, aVer, data.m_Unknown3 );
1700
1701 data.m_StrGraphicPtr = aStream.ReadU32();
1702
1703 ReadCond( aStream, aVer, data.m_PtrGroup_17x );
1704 ReadCond( aStream, aVer, data.m_Unknown4 );
1705
1706 if( data.m_Font16x.exists( aVer ) )
1707 {
1708 data.m_Font16x = ParseTextProps( aStream );
1709 }
1710
1711 ReadCond( aStream, aVer, data.m_Ptr2 );
1712
1713 data.m_CoordsX = aStream.ReadU32();
1714 data.m_CoordsY = aStream.ReadU32();
1715
1716 data.m_Unknown5 = aStream.ReadU32();
1717 data.m_Rotation = aStream.ReadU32();
1718
1719 ReadCond( aStream, aVer, data.m_PtrGroup_16x );
1720
1721 return block;
1722}
1723
1724
1725static std::unique_ptr<BLOCK_BASE> ParseBlock_0x31_SGRAPHIC( FILE_STREAM& aStream, FMT_VER aVer )
1726{
1727 auto block = std::make_unique<BLOCK<BLK_0x31_SGRAPHIC>>( 0x31, aStream.Position() );
1728
1729 auto& data = block->GetData();
1730
1731 data.m_T = aStream.ReadU8();
1732
1733 {
1734 const uint16_t layer = aStream.ReadU16();
1735
1736 switch( layer )
1737 {
1738 case 0xF001: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::BOT_TEXT; break;
1739 case 0xF101: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_TEXT; break;
1740 case 0xF609: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::BOT_PIN; break;
1741 case 0xF709: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_PIN; break;
1742 case 0xF801: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_PIN_LABEL; break;
1743 case 0xFA0D: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::BOT_REFDES; break;
1744 case 0xFB0D: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::TOP_REFDES; break;
1745 default: data.m_Layer = BLK_0x31_SGRAPHIC::STRING_LAYER::UNKNOWN; break;
1746 }
1747 }
1748
1749 data.m_Key = aStream.ReadU32();
1750 data.m_StrGraphicWrapperPtr = aStream.ReadU32();
1751
1752 data.m_CoordsX = aStream.ReadU32();
1753 data.m_CoordsY = aStream.ReadU32();
1754
1755 data.m_Unknown = aStream.ReadU16();
1756 data.m_Len = aStream.ReadU16();
1757
1758 ReadCond( aStream, aVer, data.m_Un2 );
1759
1760 data.m_Value = aStream.ReadStringFixed( data.m_Len, true );
1761
1762 return block;
1763}
1764
1765
1766static std::unique_ptr<BLOCK_BASE> ParseBlock_0x32_PLACED_PAD( FILE_STREAM& aStream, FMT_VER aVer )
1767{
1768 auto block = std::make_unique<BLOCK<BLK_0x32_PLACED_PAD>>( 0x32, aStream.Position() );
1769
1770 auto& data = block->GetData();
1771
1772 data.m_Type = aStream.ReadU8();
1773 data.m_Layer = ParseLayerInfo( aStream );
1774 data.m_Key = aStream.ReadU32();
1775 data.m_Next = aStream.ReadU32();
1776 data.m_NetPtr = aStream.ReadU32();
1777 data.m_Flags = aStream.ReadU32();
1778
1779 ReadCond( aStream, aVer, data.m_Prev );
1780
1781 data.m_NextInFp = aStream.ReadU32();
1782 data.m_ParentFp = aStream.ReadU32();
1783 data.m_Track = aStream.ReadU32();
1784 data.m_PadPtr = aStream.ReadU32();
1785 data.m_Ptr6 = aStream.ReadU32();
1786 data.m_Ratline = aStream.ReadU32();
1787 data.m_PtrPinNumber = aStream.ReadU32();
1788 data.m_NextInCompInst = aStream.ReadU32();
1789
1790 ReadCond( aStream, aVer, data.m_Unknown2 );
1791
1792 data.m_NameText = aStream.ReadU32();
1793 data.m_Ptr11 = aStream.ReadU32();
1794
1795 for( size_t i = 0; i < data.m_Coords.size(); ++i )
1796 {
1797 data.m_Coords[i] = aStream.ReadS32();
1798 }
1799
1800 return block;
1801}
1802
1803
1804static std::unique_ptr<BLOCK_BASE> ParseBlock_0x33_VIA( FILE_STREAM& aStream, FMT_VER aVer )
1805{
1806 auto block = std::make_unique<BLOCK<BLK_0x33_VIA>>( 0x33, aStream.Position() );
1807
1808 auto& data = block->GetData();
1809
1810 aStream.Skip( 1 );
1811
1812 data.m_LayerInfo = ParseLayerInfo( aStream );
1813 data.m_Key = aStream.ReadU32();
1814 data.m_Next = aStream.ReadU32();
1815 data.m_NetPtr = aStream.ReadU32();
1816 data.m_Unknown2 = aStream.ReadU32();
1817
1818 ReadCond( aStream, aVer, data.m_Unknown3 );
1819
1820 data.m_UnknownPtr1 = aStream.ReadU32();
1821
1822 ReadCond( aStream, aVer, data.m_UnknownPtr2 );
1823
1824 data.m_CoordsX = aStream.ReadS32();
1825 data.m_CoordsY = aStream.ReadS32();
1826
1827 data.m_Connection = aStream.ReadU32();
1828 data.m_Padstack = aStream.ReadU32();
1829 data.m_UnknownPtr5 = aStream.ReadU32();
1830 data.m_UnknownPtr6 = aStream.ReadU32();
1831
1832 data.m_Unknown4 = aStream.ReadU32();
1833 data.m_Unknown5 = aStream.ReadU32();
1834
1835 for( size_t i = 0; i < data.m_BoundingBoxCoords.size(); ++i )
1836 {
1837 data.m_BoundingBoxCoords[i] = aStream.ReadS32();
1838 }
1839
1840 return block;
1841}
1842
1843
1844static std::unique_ptr<BLOCK_BASE> ParseBlock_0x34_KEEPOUT( FILE_STREAM& aStream, FMT_VER aVer )
1845{
1846 auto block = std::make_unique<BLOCK<BLK_0x34_KEEPOUT>>( 0x34, aStream.Position() );
1847
1848 auto& data = block->GetData();
1849
1850 data.m_T = aStream.ReadU8();
1851 data.m_Layer = ParseLayerInfo( aStream );
1852 data.m_Key = aStream.ReadU32();
1853 data.m_Next = aStream.ReadU32();
1854 data.m_Ptr1 = aStream.ReadU32();
1855
1856 ReadCond( aStream, aVer, data.m_Unknown1 );
1857
1858 data.m_Flags = aStream.ReadU32();
1859 data.m_FirstSegmentPtr = aStream.ReadU32();
1860 data.m_Ptr3 = aStream.ReadU32();
1861 data.m_Unknown2 = aStream.ReadU32();
1862
1863 return block;
1864}
1865
1866
1867static std::unique_ptr<BLOCK_BASE> ParseBlock_0x35( FILE_STREAM& aStream, FMT_VER aVer )
1868{
1869 auto block = std::make_unique<BLOCK<BLK_0x35_FILE_REF>>( 0x35, aStream.Position() );
1870
1871 auto& data = block->GetData();
1872
1873 data.m_T2 = aStream.ReadU8();
1874 data.m_T3 = aStream.ReadU16();
1875 aStream.ReadBytes( data.m_Content.data(), data.m_Content.size() );
1876
1877 return block;
1878}
1879
1880
1881static std::unique_ptr<BLOCK_BASE> ParseBlock_0x36( FILE_STREAM& aStream, FMT_VER aVer )
1882{
1883 auto block = std::make_unique<BLOCK<BLK_0x36_DEF_TABLE>>( 0x36, aStream.Position() );
1884
1885 auto& data = block->GetData();
1886
1887 aStream.Skip( 1 );
1888
1889 data.m_Code = aStream.ReadU16();
1890 data.m_Key = aStream.ReadU32();
1891 data.m_Next = aStream.ReadU32();
1892
1893 ReadCond( aStream, aVer, data.m_Unknown1 );
1894
1895 data.m_NumItems = aStream.ReadU32();
1896 data.m_Count = aStream.ReadU32();
1897 data.m_LastIdx = aStream.ReadU32();
1898 data.m_Unknown2 = aStream.ReadU32();
1899
1900 ReadCond( aStream, aVer, data.m_Unknown3 );
1901
1902 if( data.m_NumItems > 1000000 )
1903 {
1904 THROW_IO_ERROR( wxString::Format(
1905 "Block 0x36 item count %u exceeds limit at offset %#010zx",
1906 data.m_NumItems, aStream.Position() ) );
1907 }
1908
1909 data.m_Items.reserve( data.m_NumItems );
1910 for( uint32_t i = 0; i < data.m_NumItems; ++i )
1911 {
1912 switch( data.m_Code )
1913 {
1914 case 0x02:
1915 {
1917
1918 item.m_String = aStream.ReadStringFixed( 32, true );
1919 ReadArrayU32( aStream, item.m_Xs );
1920 ReadCond( aStream, aVer, item.m_Ys );
1921 ReadCond( aStream, aVer, item.m_Zs );
1922
1923 data.m_Items.emplace_back( std::move( item ) );
1924 break;
1925 }
1926 case 0x03:
1927 {
1929 if( aVer >= FMT_VER::V_172 )
1930 item.m_Str = aStream.ReadStringFixed( 64, true );
1931 else
1932 item.m_Str16x = aStream.ReadStringFixed( 32, true );
1933
1934 ReadCond( aStream, aVer, item.m_Unknown1 );
1935
1936 data.m_Items.emplace_back( std::move( item ) );
1937 break;
1938 }
1939 case 0x05:
1940 {
1942
1943 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
1944
1945 data.m_Items.emplace_back( std::move( item ) );
1946 break;
1947 }
1948 case 0x06:
1949 {
1951
1952 item.m_N = aStream.ReadU16();
1953 item.m_R = aStream.ReadU8();
1954 item.m_S = aStream.ReadU8();
1955 item.m_Unknown1 = aStream.ReadU32();
1956
1957 ReadCond( aStream, aVer, item.m_Unknown2 );
1958
1959 data.m_Items.emplace_back( std::move( item ) );
1960 break;
1961 }
1962 case 0x08:
1963 {
1965
1966 item.m_A = aStream.ReadU32();
1967 item.m_B = aStream.ReadU32();
1968 item.m_CharHeight = aStream.ReadU32();
1969 item.m_CharWidth = aStream.ReadU32();
1970
1971 ReadCond( aStream, aVer, item.m_Unknown2 );
1972
1973 item.m_CharacterSpace = aStream.ReadU32();
1974 item.m_LineSpace = aStream.ReadU32();
1975 item.m_Unknown3 = aStream.ReadU32();
1976 item.m_StrokeWidth = aStream.ReadU32();
1977
1978 ReadCond( aStream, aVer, item.m_Ys );
1979
1980 data.m_Items.emplace_back( std::move( item ) );
1981 break;
1982 }
1983 case 0x0B:
1984 {
1986 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
1987 data.m_Items.emplace_back( std::move( item ) );
1988 break;
1989 }
1990 case 0x0C:
1991 {
1993 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
1994 data.m_Items.emplace_back( std::move( item ) );
1995 break;
1996 }
1997 case 0x0D:
1998 {
2000 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2001 data.m_Items.emplace_back( std::move( item ) );
2002 break;
2003 }
2004 case 0x0F:
2005 {
2007 item.m_Key = aStream.ReadU32();
2008 ReadArrayU32( aStream, item.m_Ptrs );
2009 item.m_Ptr2 = aStream.ReadU32();
2010 data.m_Items.emplace_back( std::move( item ) );
2011 break;
2012 }
2013 case 0x10:
2014 {
2016 aStream.ReadBytes( item.m_Unknown.data(), item.m_Unknown.size() );
2017 ReadCond( aStream, aVer, item.m_Unknown2 );
2018 data.m_Items.emplace_back( std::move( item ) );
2019 break;
2020 }
2021 default: THROW_IO_ERROR( wxString::Format( "Unknown substruct type %#02x in block 0x36", data.m_Code ) );
2022 }
2023 }
2024
2025 return block;
2026}
2027
2028
2029static std::unique_ptr<BLOCK_BASE> ParseBlock_0x37( FILE_STREAM& aStream, FMT_VER aVer )
2030{
2031 auto block = std::make_unique<BLOCK<BLK_0x37_PTR_ARRAY>>( 0x37, aStream.Position() );
2032
2033 auto& data = block->GetData();
2034
2035 data.m_T = aStream.ReadU8();
2036 data.m_T2 = aStream.ReadU16();
2037 data.m_Key = aStream.ReadU32();
2038 data.m_GroupPtr = aStream.ReadU32();
2039 data.m_Next = aStream.ReadU32();
2040 data.m_Capacity = aStream.ReadU32();
2041 data.m_Count = aStream.ReadU32();
2042 data.m_Unknown2 = aStream.ReadU32();
2043
2044 ReadCond( aStream, aVer, data.m_Unknown3 );
2045
2046 ReadArrayU32( aStream, data.m_Ptrs );
2047
2048 return block;
2049}
2050
2051
2052static std::unique_ptr<BLOCK_BASE> ParseBlock_0x38_FILM( FILE_STREAM& aStream, FMT_VER aVer )
2053{
2054 auto block = std::make_unique<BLOCK<BLK_0x38_FILM>>( 0x38, aStream.Position() );
2055
2056 auto& data = block->GetData();
2057
2058 aStream.Skip( 3 );
2059
2060 data.m_Key = aStream.ReadU32();
2061 data.m_Next = aStream.ReadU32();
2062 data.m_LayerList = aStream.ReadU32();
2063
2064 if( data.m_FilmName.exists( aVer ) )
2065 {
2066 data.m_FilmName = aStream.ReadStringFixed( 20, true );
2067 }
2068
2069 ReadCond( aStream, aVer, data.m_LayerNameStr );
2070 ReadCond( aStream, aVer, data.m_Unknown2 );
2071
2072 for( size_t i = 0; i < data.m_UnknownArray1.size(); ++i )
2073 {
2074 data.m_UnknownArray1[i] = aStream.ReadU32();
2075 }
2076
2077 ReadCond( aStream, aVer, data.m_Unknown3 );
2078
2079 return block;
2080}
2081
2082
2083static std::unique_ptr<BLOCK_BASE> ParseBlock_0x39_FILM_LAYER_LIST( FILE_STREAM& aStream, FMT_VER aVer )
2084{
2085 auto block = std::make_unique<BLOCK<BLK_0x39_FILM_LAYER_LIST>>( 0x39, aStream.Position() );
2086
2087 auto& data = block->GetData();
2088
2089 aStream.Skip( 3 );
2090
2091 data.m_Key = aStream.ReadU32();
2092 data.m_Parent = aStream.ReadU32();
2093 data.m_Head = aStream.ReadU32();
2094
2095 for( size_t i = 0; i < data.m_X.size(); ++i )
2096 {
2097 data.m_X[i] = aStream.ReadU16();
2098 }
2099
2100 return block;
2101}
2102
2103
2104static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3A_FILM_LIST_NODE( FILE_STREAM& aStream, FMT_VER aVer )
2105{
2106 auto block = std::make_unique<BLOCK<BLK_0x3A_FILM_LIST_NODE>>( 0x3A, aStream.Position() );
2107
2108 auto& data = block->GetData();
2109
2110 aStream.Skip( 1 );
2111
2112 data.m_Layer = ParseLayerInfo( aStream );
2113 data.m_Key = aStream.ReadU32();
2114 data.m_Next = aStream.ReadU32();
2115 data.m_Unknown = aStream.ReadU32();
2116
2117 ReadCond( aStream, aVer, data.m_Unknown1 );
2118
2119 return block;
2120}
2121
2122
2123static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3B( FILE_STREAM& aStream, FMT_VER aVer )
2124{
2125 auto block = std::make_unique<BLOCK<BLK_0x3B_PROPERTY>>( 0x3B, aStream.Position() );
2126
2127 auto& data = block->GetData();
2128
2129 data.m_T = aStream.ReadU8();
2130 data.m_SubType = aStream.ReadU16();
2131 data.m_Len = aStream.ReadU32();
2132
2133 data.m_Name = aStream.ReadStringFixed( 128, true );
2134 data.m_Type = aStream.ReadStringFixed( 32, true );
2135
2136 data.m_Unknown1 = aStream.ReadU32();
2137 data.m_Unknown2 = aStream.ReadU32();
2138
2139 ReadCond( aStream, aVer, data.m_Unknown3 );
2140
2141 data.m_Value = aStream.ReadStringFixed( data.m_Len, true );
2142
2143 return block;
2144}
2145
2146
2147static std::unique_ptr<BLOCK_BASE> ParseBlock_0x3C( FILE_STREAM& aStream, FMT_VER aVer )
2148{
2149 auto block = std::make_unique<BLOCK<BLK_0x3C_KEY_LIST>>( 0x3C, aStream.Position() );
2150
2151 auto& data = block->GetData();
2152
2153 data.m_T = aStream.ReadU8();
2154 data.m_T2 = aStream.ReadU16();
2155 data.m_Key = aStream.ReadU32();
2156
2157 ReadCond( aStream, aVer, data.m_Unknown );
2158
2159 data.m_NumEntries = aStream.ReadU32();
2160
2161 if( data.m_NumEntries > 1000000 )
2162 {
2163 THROW_IO_ERROR( wxString::Format(
2164 "Block 0x3C entry count %u exceeds limit at offset %#010zx",
2165 data.m_NumEntries, aStream.Position() ) );
2166 }
2167
2168 data.m_Entries.reserve( data.m_NumEntries );
2169 for( uint32_t i = 0; i < data.m_NumEntries; ++i )
2170 {
2171 data.m_Entries.push_back( aStream.ReadU32() );
2172 }
2173
2174 return block;
2175}
2176
2177
2178std::unique_ptr<BLOCK_BASE> ALLEGRO::BLOCK_PARSER::ParseBlock( bool& aEndOfObjectsMarker )
2179{
2180 // Read the type of the object
2181 // The file can end here without error.
2182 uint8_t type = 0x00;
2183 if( !m_stream.GetU8( type ) )
2184 {
2185 aEndOfObjectsMarker = true;
2186 return nullptr;
2187 }
2188
2189 std::unique_ptr<BLOCK_BASE> block;
2190
2191 switch( type )
2192 {
2193 case 0x01:
2194 {
2196 break;
2197 }
2198 case 0x03:
2199 {
2200 block = ParseBlock_0x03( m_stream, m_ver );
2201 break;
2202 }
2203 case 0x04:
2204 {
2206 break;
2207 }
2208 case 0x05:
2209 {
2211 break;
2212 }
2213 case 0x06:
2214 {
2215 block = ParseBlock_0x06( m_stream, m_ver );
2216 break;
2217 }
2218 case 0x07:
2219 {
2220 block = ParseBlock_0x07( m_stream, m_ver );
2221 break;
2222 }
2223 case 0x08:
2224 {
2225 block = ParseBlock_0x08( m_stream, m_ver );
2226 break;
2227 }
2228 case 0x09:
2229 {
2230 block = ParseBlock_0x09( m_stream, m_ver );
2231 break;
2232 }
2233 case 0x0A:
2234 {
2236 break;
2237 }
2238 case 0x0C:
2239 {
2240 block = ParseBlock_0x0C( m_stream, m_ver );
2241 break;
2242 }
2243 case 0x0D:
2244 {
2246 break;
2247 }
2248 case 0x0E:
2249 {
2250 block = ParseBlock_0x0E( m_stream, m_ver );
2251 break;
2252 }
2253 case 0x0F:
2254 {
2255 block = ParseBlock_0x0F( m_stream, m_ver );
2256 break;
2257 }
2258 case 0x10:
2259 {
2260 block = ParseBlock_0x10( m_stream, m_ver );
2261 break;
2262 }
2263 case 0x11:
2264 {
2265 block = ParseBlock_0x11( m_stream, m_ver );
2266 break;
2267 }
2268 case 0x12:
2269 {
2270 block = ParseBlock_0x12( m_stream, m_ver );
2271 break;
2272 }
2273 case 0x14:
2274 {
2275 block = ParseBlock_0x14( m_stream, m_ver );
2276 break;
2277 }
2278 case 0x15:
2279 case 0x16:
2280 case 0x17:
2281 {
2283 break;
2284 }
2285 case 0x1B:
2286 {
2288 break;
2289 }
2290 case 0x1C:
2291 {
2293 break;
2294 }
2295 case 0x1D:
2296 {
2297 block = ParseBlock_0x1D( m_stream, m_ver );
2298 break;
2299 }
2300 case 0x1E:
2301 {
2302 block = ParseBlock_0x1E( m_stream, m_ver );
2303 break;
2304 }
2305 case 0x1F:
2306 {
2307 block = ParseBlock_0x1F( m_stream, m_ver );
2308 break;
2309 }
2310 case 0x20:
2311 {
2312 block = ParseBlock_0x20( m_stream, m_ver );
2313 break;
2314 }
2315 case 0x21:
2316 {
2317 block = ParseBlock_0x21( m_stream, m_ver );
2318 break;
2319 }
2320 case 0x22:
2321 {
2322 block = ParseBlock_0x22( m_stream, m_ver );
2323 break;
2324 }
2325 case 0x23:
2326 {
2328 break;
2329 }
2330 case 0x24:
2331 {
2333 break;
2334 }
2335 case 0x26:
2336 {
2337 block = ParseBlock_0x26( m_stream, m_ver );
2338 break;
2339 }
2340 case 0x27:
2341 {
2342 if( m_x27_end <= m_stream.Position() )
2343 {
2345 wxString::Format( "Current offset %#010zx is at or past the expected end of block 0x27 at %#010zx",
2346 m_stream.Position(), m_x27_end ) );
2347 }
2349 break;
2350 }
2351 case 0x28:
2352 {
2354 break;
2355 }
2356 case 0x29:
2357 {
2359 break;
2360 }
2361 case 0x2A:
2362 {
2363 block = ParseBlock_0x2A( m_stream, m_ver );
2364 break;
2365 }
2366 case 0x2B:
2367 {
2368 block = ParseBlock_0x2B( m_stream, m_ver );
2369 break;
2370 }
2371 case 0x2C:
2372 {
2374 break;
2375 }
2376 case 0x2D:
2377 {
2378 block = ParseBlock_0x2D( m_stream, m_ver );
2379 break;
2380 }
2381 case 0x2E:
2382 {
2383 block = ParseBlock_0x2E( m_stream, m_ver );
2384 break;
2385 }
2386 case 0x2F:
2387 {
2388 block = ParseBlock_0x2F( m_stream, m_ver );
2389 break;
2390 }
2391 case 0x30:
2392 {
2394 break;
2395 }
2396 case 0x31:
2397 {
2399 break;
2400 }
2401 case 0x32:
2402 {
2404 break;
2405 }
2406 case 0x33:
2407 {
2409 break;
2410 }
2411 case 0x34:
2412 {
2414 break;
2415 }
2416 case 0x35:
2417 {
2418 block = ParseBlock_0x35( m_stream, m_ver );
2419 break;
2420 }
2421 case 0x36:
2422 {
2423 block = ParseBlock_0x36( m_stream, m_ver );
2424 break;
2425 }
2426 case 0x37:
2427 {
2428 block = ParseBlock_0x37( m_stream, m_ver );
2429 break;
2430 }
2431 case 0x38:
2432 {
2434 break;
2435 }
2436 case 0x39:
2437 {
2439 break;
2440 }
2441 case 0x3A:
2442 {
2444 break;
2445 }
2446 case 0x3B:
2447 {
2448 block = ParseBlock_0x3B( m_stream, m_ver );
2449 break;
2450 }
2451 case 0x3C:
2452 {
2453 block = ParseBlock_0x3C( m_stream, m_ver );
2454 break;
2455 }
2456 case 0x00:
2457 {
2458 // Block type 0x00 marks the end of the objects section
2459 aEndOfObjectsMarker = true;
2460 break;
2461 }
2462 default:
2463 break;
2464 }
2465
2466 return block;
2467}
2468
2469
2471{
2472 const FMT_VER ver = aBoard.m_FmtVer;
2473
2474 if( m_progressReporter )
2475 {
2476 m_progressReporter->AdvancePhase( _( "Parsing Allegro objects" ) );
2477 // This isn't exactly the number we seem to parse, but it's very close
2478 m_progressReporter->SetMaxProgress( static_cast<int>( aBoard.m_Header->m_ObjectCount ) );
2479 }
2480
2481 BLOCK_PARSER blockParser( m_stream, ver, aBoard.m_Header->Get_0x27_End() );
2482
2483 THROTTLE refreshThrottle( std::chrono::milliseconds( 100 ) );
2484
2485 while( true )
2486 {
2487 const size_t offset = m_stream.Position();
2488
2489 // This seems to be always true and is quite useful for debugging out-of-sync objects
2490 wxASSERT_MSG( offset % 4 == 0,
2491 wxString::Format( "Allegro object at %#010zx, offset not aligned to 4 bytes", offset ) );
2492
2493 // Peek at the block type byte before ParseBlock consumes it so we
2494 // have the value available for error messages if the type is unknown
2495 // and ParseBlock returns nullptr.
2496 uint8_t blockTypeByte = 0;
2497 m_stream.GetU8( blockTypeByte );
2498 m_stream.Seek( offset );
2499
2500 bool endOfObjectsMarker = false;
2501 std::unique_ptr<BLOCK_BASE> block = blockParser.ParseBlock( endOfObjectsMarker );
2502
2503 if( endOfObjectsMarker )
2504 {
2505 if( ver >= FMT_VER::V_180 )
2506 {
2507 // V18 files can have zero-padded gaps between block groups. Skip
2508 // consecutive zero bytes and check if more blocks follow.
2509 size_t scanPos = m_stream.Position();
2510 uint8_t nextByte = 0;
2511
2512 while( m_stream.GetU8( nextByte ) && nextByte == 0x00 )
2513 scanPos = m_stream.Position();
2514
2515 if( nextByte > 0x00 && nextByte <= 0x3C )
2516 {
2517 size_t blockStart = scanPos;
2518
2519 if( blockStart % 4 != 0 )
2520 blockStart -= ( blockStart % 4 );
2521
2522 // After backward alignment the byte at blockStart may
2523 // differ from the non-zero byte we found. Verify it
2524 // still looks like a valid block type before continuing.
2525 uint8_t alignedByte = 0;
2526 m_stream.Seek( blockStart );
2527 m_stream.GetU8( alignedByte );
2528 m_stream.Seek( blockStart );
2529
2530 if( alignedByte == 0x00 || alignedByte > 0x3C )
2531 break;
2532
2533 wxLogTrace( traceAllegroParser,
2534 wxString::Format( "V18 zero gap from %#010zx to %#010zx, "
2535 "continuing at block type %#04x",
2536 offset, blockStart, nextByte ) );
2537 continue;
2538 }
2539 }
2540
2541 if( wxLog::IsAllowedTraceMask( traceAllegroParser ) )
2542 {
2543 wxLogTrace( traceAllegroParser,
2544 wxString::Format( "End of objects marker (0x00) at index %zu, offset %#010zx",
2545 aBoard.GetObjectCount(), offset ) );
2546 }
2547
2548 break;
2549 }
2550
2551 if( !block )
2552 {
2553 if( !m_endAtUnknownBlock )
2554 {
2555 THROW_IO_ERROR( wxString::Format(
2556 "Do not have parser for block index %zu type %#02x available at offset %#010zx",
2557 aBoard.GetObjectCount(), blockTypeByte, offset ) );
2558 }
2559 else
2560 {
2561 wxLogTrace( traceAllegroParser,
2562 wxString::Format( "Ending at unknown block, index %zu type %#04x at offset %#010zx",
2563 aBoard.GetObjectCount(), blockTypeByte, offset ) );
2564
2565 wxFAIL_MSG( "Failed to create block" );
2566 return;
2567 }
2568 }
2569 else
2570 {
2571 if( wxLog::IsAllowedTraceMask( traceAllegroParser ) )
2572 {
2573 wxLogTrace( traceAllegroParserBlocks,
2574 wxString::Format( "Added block %zu, type %#04x from %#010zx to %#010zx",
2575 aBoard.GetObjectCount(), block->GetBlockType(), offset,
2576 m_stream.Position() ) );
2577 }
2578
2579 aBoard.InsertBlock( std::move( block ) );
2580
2581 if( m_progressReporter )
2582 {
2583 m_progressReporter->AdvanceProgress();
2584
2585 if( ( aBoard.GetObjectCount() & 0x3F ) == 0 && refreshThrottle.Ready() )
2586 m_progressReporter->KeepRefreshing();
2587 }
2588 }
2589 }
2590}
2591
2592
2593template <typename T>
2594void dumpLL( const char* name, const T& aLL )
2595{
2596 if constexpr( std::is_same_v<T, FILE_HEADER::LINKED_LIST> )
2597 {
2598 wxLogTrace( traceAllegroParser, " LL %-20s head=%#010x tail=%#010x", name, aLL.m_Head, aLL.m_Tail );
2599 }
2600 else if constexpr( std::is_base_of_v<COND_FIELD_BASE<FILE_HEADER::LINKED_LIST>, T> )
2601 {
2602 if( aLL.has_value() )
2603 dumpLL( name, aLL.value() );
2604 }
2605}
2606
2607
2608std::unique_ptr<BRD_DB> ALLEGRO::PARSER::Parse()
2609{
2610 std::unique_ptr<BRD_DB> board = std::make_unique<BRD_DB>();
2611
2612 if( m_progressReporter )
2613 {
2614 m_progressReporter->AddPhases( 2 );
2615 m_progressReporter->AdvancePhase( "Reading file header" );
2616 }
2617
2618 PROF_TIMER parseTimer;
2619 HEADER_PARSER headerParser( m_stream );
2620
2621 try
2622 {
2623 board->m_Header = headerParser.ParseHeader();
2624
2625 if( !board->m_Header )
2626 {
2627 THROW_IO_ERROR( "Failed to parse file header" );
2628 }
2629
2630 board->m_FmtVer = headerParser.GetFormatVersion();
2631
2632 {
2633 wxLogTrace( traceAllegroParser, "Header linked lists (ver=%#010x):",
2634 board->m_Header->m_Magic );
2635
2636 dumpLL( "V18_1", board->m_Header->m_LL_V18_1 );
2637 dumpLL( "V18_2", board->m_Header->m_LL_V18_2 );
2638 dumpLL( "V18_3", board->m_Header->m_LL_V18_3 );
2639 dumpLL( "V18_4", board->m_Header->m_LL_V18_4 );
2640 dumpLL( "V18_5", board->m_Header->m_LL_V18_5 );
2641
2642 dumpLL( "0x04", board->m_Header->m_LL_0x04 );
2643 dumpLL( "0x06", board->m_Header->m_LL_0x06 );
2644 dumpLL( "0x0C", board->m_Header->m_LL_0x0C );
2645 dumpLL( "Shapes", board->m_Header->m_LL_Shapes );
2646 dumpLL( "0x14", board->m_Header->m_LL_0x14 );
2647 dumpLL( "0x1B_Nets", board->m_Header->m_LL_0x1B_Nets );
2648 dumpLL( "0x1C", board->m_Header->m_LL_0x1C );
2649 dumpLL( "0x24_0x28", board->m_Header->m_LL_0x24_0x28 );
2650 dumpLL( "Unknown1", board->m_Header->m_LL_Unknown1 );
2651 dumpLL( "0x2B", board->m_Header->m_LL_0x2B );
2652 dumpLL( "0x03_0x30", board->m_Header->m_LL_0x03_0x30 );
2653 dumpLL( "0x0A", board->m_Header->m_LL_0x0A );
2654 dumpLL( "0x1D_0x1E_0x1F", board->m_Header->m_LL_0x1D_0x1E_0x1F );
2655 dumpLL( "Unknown2", board->m_Header->m_LL_Unknown2 );
2656 dumpLL( "0x38", board->m_Header->m_LL_0x38 );
2657 dumpLL( "0x2C", board->m_Header->m_LL_0x2C );
2658 dumpLL( "0x0C_2", board->m_Header->m_LL_0x0C_2 );
2659 dumpLL( "Unknown3", board->m_Header->m_LL_Unknown3 );
2660 dumpLL( "Unknown5", board->m_Header->m_LL_Unknown5_preV18 );
2661 dumpLL( "Unknown5", board->m_Header->m_LL_Unknown5_V18 );
2662 dumpLL( "0x36", board->m_Header->m_LL_0x36 );
2663 dumpLL( "Unknown6", board->m_Header->m_LL_Unknown6 );
2664 dumpLL( "0x0A_2", board->m_Header->m_LL_0x0A_2 );
2665
2666 dumpLL( "V18_6", board->m_Header->m_LL_V18_6 );
2667 }
2668 }
2669 catch( const IO_ERROR& e )
2670 {
2671 wxString s;
2672 s += wxString::Format( "Error parsing Allegro file: %s\n", e.What() );
2673 s += wxString::Format( "Stream position: %#010lx\n", m_stream.Position() );
2674
2675 if( board->m_Header )
2676 s += wxString::Format( "File magic: %#010x\n", board->m_Header->m_Magic );
2677 else
2678 s += wxString::Format( "File magic: Unknown\n" );
2679
2680 THROW_IO_ERROR( s );
2681 }
2682
2683 wxLogTrace( traceAllegroPerf, wxT( " ReadHeader: %.3f ms" ), parseTimer.msecs( true ) ); //format:allow
2684
2685 if( board->m_FmtVer == FMT_VER::V_PRE_V16 )
2686 {
2687 wxString verStr( board->m_Header->m_AllegroVersion.data(), 60 );
2688 verStr.Trim();
2689
2690 THROW_IO_ERROR( wxString::Format(
2691 _( "This file was created with %s, which uses a binary format that "
2692 "predates Allegro 16.0 and is not supported by this importer.\n\n"
2693 "To import this design, open it in Cadence Allegro PCB Editor "
2694 "version 16.0 or later and re-save, then import the resulting file." ),
2695 verStr ) );
2696 }
2697
2698 const uint32_t stringsCount = board->m_Header->GetStringsCount();
2699 board->ReserveCapacity( board->m_Header->m_ObjectCount, stringsCount );
2700
2701 // Skip DB_OBJ creation for high-volume types (segments, graphics, arcs) that the
2702 // BOARD_BUILDER accesses only through raw BLOCK_BASE. Saves millions of allocations.
2703 board->SetLeanMode( true );
2704
2705 try
2706 {
2707 ReadStringMap( m_stream, *board, stringsCount );
2708
2709 wxLogTrace( traceAllegroPerf, wxT( " ReadStringMap (%u strings): %.3f ms" ), //format:allow
2710 stringsCount, parseTimer.msecs( true ) );
2711
2712 readObjects( *board );
2713
2714 wxLogTrace( traceAllegroPerf, wxT( " readObjects (%zu objects): %.3f ms" ), //format:allow
2715 board->GetObjectCount(), parseTimer.msecs( true ) );
2716 }
2717 catch( const IO_ERROR& e )
2718 {
2719 wxString s;
2720 s += wxString::Format( "Error parsing Allegro file: %s\n", e.What() );
2721 s += wxString::Format( "Stream position: %#010lx\n", m_stream.Position() );
2722
2723 if( board->m_Header )
2724 s += wxString::Format( "File magic: %#010x\n", board->m_Header->m_Magic );
2725 else
2726 s += wxString::Format( "File magic: Unknown\n" );
2727
2728 THROW_IO_ERROR( s );
2729 }
2730
2731 // Now the object are read, resolve the DB links
2732 board->ResolveAndValidate();
2733
2734 wxLogTrace( traceAllegroPerf, wxT( " ResolveAndValidate: %.3f ms" ), parseTimer.msecs( true ) ); //format:allow
2735 wxLogTrace( traceAllegroPerf, wxT( " Phase 1 total: %.3f ms" ), parseTimer.msecs() ); //format:allow
2736
2737 return board;
2738}
2739
2740
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 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 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 void ReadStringMap(FILE_STREAM &stream, DB &aDb, uint32_t count)
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 database that represents a .brd file (amd presumably .dra)
Definition allegro_db.h:949
std::unique_ptr< FILE_HEADER > m_Header
void InsertBlock(std::unique_ptr< BLOCK_BASE > aBlock) override
An ALLEGRO::DB is the represention of the actual data stored within an Allegro file,...
Definition allegro_db.h:249
void AddString(uint32_t aKey, wxString &&aStr)
Definition allegro_db.h:257
size_t GetObjectCount() const
Definition allegro_db.h:259
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:49
double msecs(bool aSinceLast=false)
Definition profile.h:149
Rate-limiter that fires at most once per interval.
Definition throttle.h:35
bool Ready()
Definition throttle.h:48
#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
FMT_VER
The format of an Allego file.
static const wxChar *const traceAllegroPerf
std::array< uint32_t, 20 > m_Entries
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_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.
static const size_t STRING_TABLE_OFFSET
FMT_VER m_FmtVer
What version is this file?
A type that is always false.
KIBIS_COMPONENT * comp
wxString result
Test unit parsing edge cases and error handling.