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