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