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