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