KiCad PCB EDA Suite
Loading...
Searching...
No Matches
cadstar_archive_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 (C) 2020-2021 Roberto Fernandez Bautista <[email protected]>
5 * Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
25#include <wx/filename.h>
26#include <wx/log.h>
27#include <wx/xml/xml.h>
28
29#include <dsnlexer.h>
32#include <eda_item.h>
33#include <eda_text.h>
34#include <macros.h>
35#include <progress_reporter.h>
36#include <string_utils.h>
37#include <trigo.h>
38
39// Ratio derived from CADSTAR default font. See doxygen comment in cadstar_archive_parser.h
40const double CADSTAR_ARCHIVE_PARSER::TXT_HEIGHT_RATIO = ( 24.0 - 5.0 ) / 24.0;
41
42// Cadstar fields and their KiCad equivalent
43const std::map<CADSTAR_ARCHIVE_PARSER::TEXT_FIELD_NAME, wxString>
45 { { TEXT_FIELD_NAME::DESIGN_TITLE, wxT( "DESIGN_TITLE" ) },
46 { TEXT_FIELD_NAME::SHORT_JOBNAME, wxT( "SHORT_JOBNAME" ) },
47 { TEXT_FIELD_NAME::LONG_JOBNAME, wxT( "LONG_JOBNAME" ) },
48 { TEXT_FIELD_NAME::NUM_OF_SHEETS, wxT( "##" ) },
49 { TEXT_FIELD_NAME::SHEET_NUMBER, wxT( "#" ) },
50 { TEXT_FIELD_NAME::SHEET_NAME, wxT( "SHEETNAME" ) },
51 { TEXT_FIELD_NAME::VARIANT_NAME, wxT( "VARIANT_NAME" ) },
52 { TEXT_FIELD_NAME::VARIANT_DESCRIPTION, wxT( "VARIANT_DESCRIPTION" ) },
53 { TEXT_FIELD_NAME::REG_USER, wxT( "REG_USER" ) },
54 { TEXT_FIELD_NAME::COMPANY_NAME, wxT( "COMPANY_NAME" ) },
55 { TEXT_FIELD_NAME::CURRENT_USER, wxT( "CURRENT_USER" ) },
56 { TEXT_FIELD_NAME::DATE, wxT( "DATE" ) },
57 { TEXT_FIELD_NAME::TIME, wxT( "TIME" ) },
58 { TEXT_FIELD_NAME::MACHINE_NAME, wxT( "MACHINE_NAME" ) } };
59
60
62{
63 wxASSERT( aNode->GetName() == wxT( "FORMAT" ) );
64
65 Type = GetXmlAttributeIDString( aNode, 0 );
66 SomeInt = GetXmlAttributeIDLong( aNode, 1 );
67 Version = GetXmlAttributeIDLong( aNode, 2 );
68}
69
70
72{
73 wxASSERT( aNode->GetName() == wxT( "TIMESTAMP" ) );
74
75 if( !GetXmlAttributeIDString( aNode, 0 ).ToLong( &Year )
76 || !GetXmlAttributeIDString( aNode, 1 ).ToLong( &Month )
77 || !GetXmlAttributeIDString( aNode, 2 ).ToLong( &Day )
78 || !GetXmlAttributeIDString( aNode, 3 ).ToLong( &Hour )
79 || !GetXmlAttributeIDString( aNode, 4 ).ToLong( &Minute )
80 || !GetXmlAttributeIDString( aNode, 5 ).ToLong( &Second ) )
81 THROW_PARSING_IO_ERROR( wxT( "TIMESTAMP" ), wxString::Format( "HEADER" ) );
82}
83
84
86{
87 wxASSERT( aNode->GetName() == wxT( "HEADER" ) );
88
89 XNODE* cNode = aNode->GetChildren();
90
91 for( ; cNode; cNode = cNode->GetNext() )
92 {
93 wxString nodeName = cNode->GetName();
94
95 if( nodeName == wxT( "FORMAT" ) )
96 {
97 Format.Parse( cNode, aContext );
98 }
99 else if( nodeName == wxT( "JOBFILE" ) )
100 {
101 JobFile = GetXmlAttributeIDString( cNode, 0 );
102 }
103 else if( nodeName == wxT( "JOBTITLE" ) )
104 {
105 JobTitle = GetXmlAttributeIDString( cNode, 0 );
106 }
107 else if( nodeName == wxT( "GENERATOR" ) )
108 {
109 Generator = GetXmlAttributeIDString( cNode, 0 );
110 }
111 else if( nodeName == wxT( "RESOLUTION" ) )
112 {
113 XNODE* subNode = cNode->GetChildren();
114
115 if( ( subNode->GetName() == wxT( "METRIC" ) )
116 && ( GetXmlAttributeIDString( subNode, 0 ) == wxT( "HUNDREDTH" ) )
117 && ( GetXmlAttributeIDString( subNode, 1 ) == wxT( "MICRON" ) ) )
118 {
119 Resolution = RESOLUTION::HUNDREDTH_MICRON;
120 }
121 else
122 {
123 // TODO Need to find out if there are other possible resolutions. Logically
124 // there must be other base units that could be used, such as "IMPERIAL INCH"
125 // or "METRIC MM" but so far none of settings in CADSTAR generated a different
126 // output resolution to "HUNDREDTH MICRON"
127 THROW_UNKNOWN_NODE_IO_ERROR( subNode->GetName(), wxT( "HEADER->RESOLUTION" ) );
128 }
129 }
130 else if( nodeName == wxT( "TIMESTAMP" ) )
131 {
132 Timestamp.Parse( cNode, aContext );
133 }
134 else
135 {
136 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "HEADER" ) );
137 }
138 }
139}
140
141
143{
144 wxASSERT( aNode->GetName() == wxT( "VMASTER" ) || aNode->GetName() == wxT( "VARIANT" ) );
145
146 ID = GetXmlAttributeIDString( aNode, 0 );
147
148 if( aNode->GetName() == wxT( "VMASTER" ) )
149 {
150 Name = GetXmlAttributeIDString( aNode, 1 );
151 Description = GetXmlAttributeIDString( aNode, 2 );
152 }
153 else
154 {
155 ParentID = GetXmlAttributeIDString( aNode, 1 );
156 Name = GetXmlAttributeIDString( aNode, 2 );
157 Description = GetXmlAttributeIDString( aNode, 3 );
158 }
159}
160
161
163{
164 wxASSERT( aNode->GetName() == wxT( "VHIERARCHY" ) );
165
166 XNODE* cNode = aNode->GetChildren();
167
168 for( ; cNode; cNode = cNode->GetNext() )
169 {
170 if( cNode->GetName() == wxT( "VMASTER" ) || cNode->GetName() == wxT( "VARIANT" ) )
171 {
172 VARIANT variant;
173 variant.Parse( cNode, aContext );
174 Variants.insert( std::make_pair( variant.ID, variant ) );
175 }
176 else
177 {
178 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), cNode->GetName() );
179 }
180 }
181}
182
183
185{
186 wxASSERT( aNode->GetName() == wxT( "LINECODE" ) );
187
188 ID = GetXmlAttributeIDString( aNode, 0 );
189 Name = GetXmlAttributeIDString( aNode, 1 );
190
191 if( !GetXmlAttributeIDString( aNode, 2 ).ToLong( &Width ) )
192 THROW_PARSING_IO_ERROR( wxT( "Line Width" ), wxString::Format( "LINECODE -> %s", Name ) );
193
194 XNODE* cNode = aNode->GetChildren();
195
196 if( !cNode || cNode->GetName() != wxT( "STYLE" ) )
197 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxString::Format( "LINECODE -> %s", Name ) );
198
199 wxString styleStr = GetXmlAttributeIDString( cNode, 0 );
200
201 if( styleStr == wxT( "SOLID" ) )
202 {
203 Style = LINESTYLE::SOLID;
204 }
205 else if( styleStr == wxT( "DASH" ) )
206 {
207 Style = LINESTYLE::DASH;
208 }
209 else if( styleStr == wxT( "DASHDOT" ) )
210 {
211 Style = LINESTYLE::DASHDOT;
212 }
213 else if( styleStr == wxT( "DASHDOTDOT" ) )
214 {
215 Style = LINESTYLE::DASHDOTDOT;
216 }
217 else if( styleStr == wxT( "DOT" ) )
218 {
219 Style = LINESTYLE::DOT;
220 }
221 else
222 {
223 THROW_UNKNOWN_PARAMETER_IO_ERROR( wxString::Format( "STYLE %s", styleStr ),
224 wxString::Format( "LINECODE -> %s", Name ) );
225 }
226}
227
228
230{
231 wxASSERT( aNode->GetName() == wxT( "HATCH" ) );
232
233 Step = GetXmlAttributeIDLong( aNode, 0 );
234 LineWidth = GetXmlAttributeIDLong( aNode, 2 );
235
236 XNODE* cNode = aNode->GetChildren();
237
238 if( !cNode || cNode->GetName() != wxT( "ORIENT" ) )
239 THROW_MISSING_NODE_IO_ERROR( wxT( "ORIENT" ), wxT( "HATCH" ) );
240
241 OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
242}
243
244
246{
247 wxASSERT( aNode->GetName() == wxT( "HATCHCODE" ) );
248
249 ID = GetXmlAttributeIDString( aNode, 0 );
250 Name = GetXmlAttributeIDString( aNode, 1 );
251
252 XNODE* cNode = aNode->GetChildren();
253 wxString location = wxString::Format( "HATCHCODE -> %s", Name );
254
255 for( ; cNode; cNode = cNode->GetNext() )
256 {
257 if( cNode->GetName() != wxT( "HATCH" ) )
258 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), location );
259
260 HATCH hatch;
261 hatch.Parse( cNode, aContext );
262 Hatches.push_back( hatch );
263 }
264}
265
266
268{
269 wxASSERT( aNode->GetName() == wxT( "FONT" ) );
270
271 Name = GetXmlAttributeIDString( aNode, 0 );
272 Modifier1 = GetXmlAttributeIDLong( aNode, 1 );
273 Modifier2 = GetXmlAttributeIDLong( aNode, 2 );
274
275 XNODE* cNode = aNode->GetChildren();
276
277 for( ; cNode; cNode = cNode->GetNext() )
278 {
279 wxString cNodeName = cNode->GetName();
280
281 if( cNodeName == wxT( "ITALIC" ) )
282 Italic = true;
283 else if( cNodeName == wxT( "KERNING" ) )
284 KerningPairs = true;
285 else
286 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
287 }
288}
289
290
292{
293 wxASSERT( aNode->GetName() == wxT( "TEXTCODE" ) );
294
295 ID = GetXmlAttributeIDString( aNode, 0 );
296 Name = GetXmlAttributeIDString( aNode, 1 );
297
298 LineWidth = GetXmlAttributeIDLong( aNode, 2 );
299 Height = GetXmlAttributeIDLong( aNode, 3 );
300 Width = GetXmlAttributeIDLong( aNode, 4 );
301
302 XNODE* cNode = aNode->GetChildren();
303
304 if( cNode )
305 {
306 if( cNode->GetName() == wxT( "FONT" ) )
307 Font.Parse( cNode, aContext );
308 else
309 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
310 }
311}
312
313
315{
316 wxASSERT( aNode->GetName() == wxT( "ROUTEREASSIGN" ) );
317
318 LayerID = GetXmlAttributeIDString( aNode, 0 );
319 OptimalWidth = GetXmlAttributeIDLong( aNode, 1, false );
320
321 XNODE* cNode = aNode->GetChildren();
322
323 for( ; cNode; cNode = cNode->GetNext() )
324 {
325 wxString cNodeName = cNode->GetName();
326
327 if( cNodeName == wxT( "NECKWIDTH" ) )
328 NeckedWidth = GetXmlAttributeIDLong( cNode, 0 );
329 else if( cNodeName == wxT( "SROUTEWIDTH" ) )
330 OptimalWidth = GetXmlAttributeIDLong( cNode, 0 );
331 else if( cNodeName == wxT( "MINWIDTH" ) )
332 MinWidth = GetXmlAttributeIDLong( cNode, 0 );
333 else if( cNodeName == wxT( "MAXWIDTH" ) )
334 MaxWidth = GetXmlAttributeIDLong( cNode, 0 );
335 else
336 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
337 }
338}
339
340
342{
343 wxASSERT( aNode->GetName() == wxT( "ROUTECODE" ) );
344
345 ID = GetXmlAttributeIDString( aNode, 0 );
346 Name = GetXmlAttributeIDString( aNode, 1 );
347 OptimalWidth = GetXmlAttributeIDLong( aNode, 2, false );
348
349 XNODE* cNode = aNode->GetChildren();
350
351 for( ; cNode; cNode = cNode->GetNext() )
352 {
353 wxString cNodeName = cNode->GetName();
354
355 if( cNodeName == wxT( "NECKWIDTH" ) )
356 {
357 NeckedWidth = GetXmlAttributeIDLong( cNode, 0 );
358 }
359 else if( cNodeName == wxT( "SROUTEWIDTH" ) )
360 {
361 OptimalWidth = GetXmlAttributeIDLong( cNode, 0 );
362 }
363 else if( cNodeName == wxT( "MINWIDTH" ) )
364 {
365 MinWidth = GetXmlAttributeIDLong( cNode, 0 );
366 }
367 else if( cNodeName == wxT( "MAXWIDTH" ) )
368 {
369 MaxWidth = GetXmlAttributeIDLong( cNode, 0 );
370 }
371 else if( cNodeName == wxT( "ROUTEREASSIGN" ) )
372 {
373 ROUTEREASSIGN routereassign;
374 routereassign.Parse( cNode, aContext );
375 RouteReassigns.push_back( routereassign );
376 }
377 else
378 {
379 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
380 }
381 }
382}
383
384
386{
387 return Base * std::pow( 10.0, Exponent );
388}
389
390
392{
393 wxASSERT( aNode->GetName() == wxT( "E" ) );
394
395 if( ( !GetXmlAttributeIDString( aNode, 0 ).ToLong( &Base ) )
396 || ( !GetXmlAttributeIDString( aNode, 1 ).ToLong( &Exponent ) ) )
397 {
398 THROW_PARSING_IO_ERROR( wxT( "Base and Exponent" ),
399 wxString::Format(
400 "%s->%s", aNode->GetParent()->GetName(), aNode->GetParent()->GetName() ) );
401 }
402}
403
404
406{
407 wxASSERT( aNode->GetName() == wxT( "PT" ) );
408
409 x = GetXmlAttributeIDLong( aNode, 0 );
410 y = GetXmlAttributeIDLong( aNode, 1 );
411}
412
413
415{
416 wxASSERT( aNode->GetName() == wxT( "PT" ) );
417
418 x = GetXmlAttributeIDLong( aNode, 0 );
419 y = GetXmlAttributeIDLong( aNode, 1 );
420}
421
422
424{
425 wxString aNodeName = aNode->GetName();
426
427 if( aNodeName == wxT( "PT" ) || aNodeName == wxT( "ACWARC" ) || aNodeName == wxT( "CWARC" )
428 || aNodeName == wxT( "CWSEMI" ) || aNodeName == wxT( "ACWSEMI" ) )
429 {
430 return true;
431 }
432 else
433 {
434 return false;
435 }
436}
437
438
440{
441 wxASSERT( IsVertex( aNode ) );
442
443 wxString aNodeName = aNode->GetName();
444
445 if( aNodeName == wxT( "PT" ) )
446 {
447 Type = VERTEX_TYPE::POINT;
448 Center.x = UNDEFINED_VALUE;
449 Center.y = UNDEFINED_VALUE;
450 End.Parse( aNode, aContext );
451 }
452 else if( aNodeName == wxT( "ACWARC" ) || aNodeName == wxT( "CWARC" ) )
453 {
454 if( aNodeName == wxT( "ACWARC" ) )
456 else
458
459 std::vector<POINT> pts = ParseAllChildPoints( aNode, aContext, true, 2 );
460
461 Center = pts[0];
462 End = pts[1];
463 }
464 else if( aNodeName == wxT( "ACWSEMI" ) || aNodeName == wxT( "CWSEMI" ) )
465 {
466 if( aNodeName == wxT( "ACWSEMI" ) )
468 else
470
471 Center.x = UNDEFINED_VALUE;
472 Center.y = UNDEFINED_VALUE;
473
474 std::vector<POINT> pts = ParseAllChildPoints( aNode, aContext, true, 1 );
475
476 End = pts[0];
477 }
478 else
479 {
480 wxASSERT_MSG( true, wxT( "Unknown VERTEX type" ) );
481 }
482}
483
484
486 const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
487 double aAccuracy ) const
488{
489 if( Type == VERTEX_TYPE::POINT )
490 {
491 aChainToAppendTo->Append( aCadstarToKicadPointCallback( End ) );
492 return;
493 }
494
495 wxCHECK_MSG( aChainToAppendTo->PointCount() > 0, /*void*/,
496 "Can't append an arc to vertex to an empty chain" );
497
498 aChainToAppendTo->Append( BuildArc( aChainToAppendTo->GetPoint( -1 ), aCadstarToKicadPointCallback),
499 aAccuracy );
500}
501
502
504 const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback ) const
505{
506 wxCHECK_MSG( Type != VERTEX_TYPE::POINT, SHAPE_ARC(),
507 "Can't build an arc for a straight segment!" );
508
509 VECTOR2I startPoint = aPrevPoint;
510 VECTOR2I endPoint = aCadstarToKicadPointCallback( End );
511 VECTOR2I centerPoint;
512
514 centerPoint = ( startPoint / 2 ) + ( endPoint / 2 );
515 else
516 centerPoint = aCadstarToKicadPointCallback( Center );
517
518 bool clockwise = Type == VERTEX_TYPE::CLOCKWISE_ARC
520
521 // A bit of a hack to figure out if we need to invert clockwise due to the transform
522 VECTOR2I transform = aCadstarToKicadPointCallback( { 500, 500 } )
523 - aCadstarToKicadPointCallback( { 0, 0 } );
524
525 if( ( transform.x > 0 && transform.y < 0 ) || ( transform.x < 0 && transform.y > 0 ) )
526 clockwise = !clockwise;
527
528 SHAPE_ARC arc;
529
530 return arc.ConstructFromStartEndCenter( startPoint, endPoint, centerPoint, clockwise );
531}
532
533
535{
536 wxASSERT( aNode->GetName() == wxT( "CUTOUT" ) );
537
538 Vertices = ParseAllChildVertices( aNode, aContext, true );
539}
540
541
543{
544 wxString aNodeName = aNode->GetName();
545
546 if( aNodeName == wxT( "OPENSHAPE" ) || aNodeName == wxT( "OUTLINE" )
547 || aNodeName == wxT( "SOLID" ) || aNodeName == wxT( "HATCHED" ) )
548 {
549 return true;
550 }
551 else
552 {
553 return false;
554 }
555}
556
557
559{
560 wxASSERT( IsShape( aNode ) );
561
562 wxString aNodeName = aNode->GetName();
563
564 if( aNodeName == wxT( "OPENSHAPE" ) )
565 {
567 Vertices = ParseAllChildVertices( aNode, aContext, true );
568 Cutouts.clear();
569 HatchCodeID = wxEmptyString;
570 }
571 else if( aNodeName == wxT( "OUTLINE" ) )
572 {
573 Type = SHAPE_TYPE::OUTLINE;
574 Vertices = ParseAllChildVertices( aNode, aContext, false );
575 Cutouts = ParseAllChildCutouts( aNode, aContext, false );
576 HatchCodeID = wxEmptyString;
577 }
578 else if( aNodeName == wxT( "SOLID" ) )
579 {
580 Type = SHAPE_TYPE::SOLID;
581 Vertices = ParseAllChildVertices( aNode, aContext, false );
582 Cutouts = ParseAllChildCutouts( aNode, aContext, false );
583 HatchCodeID = wxEmptyString;
584 }
585 else if( aNodeName == wxT( "HATCHED" ) )
586 {
587 Type = SHAPE_TYPE::HATCHED;
588 Vertices = ParseAllChildVertices( aNode, aContext, false );
589 Cutouts = ParseAllChildCutouts( aNode, aContext, false );
590 HatchCodeID = GetXmlAttributeIDString( aNode, 0 );
591 }
592 else
593 {
594 wxASSERT_MSG( true, wxT( "Unknown SHAPE type" ) );
595 }
596}
597
599 const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
600 double aAccuracy ) const
601{
602 SHAPE_LINE_CHAIN outline;
603
604 if( Vertices.size() == 0 )
605 return outline;
606
607 for( const auto& vertex : Vertices )
608 vertex.AppendToChain( &outline, aCadstarToKicadPointCallback, aAccuracy );
609
610 if( Type != SHAPE_TYPE::OPENSHAPE )
611 {
612 outline.SetClosed( true );
613
614 // Append after closing, to ensre first and last point remain the same
615 outline.Append( outline.CPoint( 0 ), true );
616 }
617
618 return outline;
619}
620
621
623 const std::function<VECTOR2I( const VECTOR2I& )> aCadstarToKicadPointCallback,
624 double aAccuracy ) const
625{
626 SHAPE_POLY_SET polyset;
627
628 wxCHECK( Type != SHAPE_TYPE::OPENSHAPE, polyset ); // We shouldn't convert openshapes to polyset!
629
630 polyset.AddOutline( OutlineAsChain( aCadstarToKicadPointCallback, aAccuracy ) );
631
632 for( const auto& cutout : Cutouts )
633 {
634 SHAPE_LINE_CHAIN hole;
635
636 if( cutout.Vertices.size() == 0 )
637 continue;
638
639 for( const auto& cutoutVertex : cutout.Vertices )
640 cutoutVertex.AppendToChain( &hole, aCadstarToKicadPointCallback, aAccuracy );
641
642 hole.SetClosed( true );
643
644 // Append after closing, to ensre first and last point remain the same
645 cutout.Vertices.at( 0 ).AppendToChain( &hole, aCadstarToKicadPointCallback, aAccuracy );
646
647 polyset.AddHole( hole );
648 }
649
650 return polyset;
651}
652
653
655{
656 wxASSERT( aNode->GetName() == wxT( "UNITS" ) );
657
658 wxString unit = GetXmlAttributeIDString( aNode, 0 );
659
660 if( unit == wxT( "CENTIMETER" ) )
661 return UNITS::CENTIMETER;
662 else if( unit == wxT( "INCH" ) )
663 return UNITS::INCH;
664 else if( unit == wxT( "METER" ) )
665 return UNITS::METER;
666 else if( unit == wxT( "MICROMETRE" ) )
667 return UNITS::MICROMETRE;
668 else if( unit == wxT( "MM" ) )
669 return UNITS::MM;
670 else if( unit == wxT( "THOU" ) )
671 return UNITS::THOU;
672 else if( unit == wxT( "DESIGN" ) )
673 return UNITS::DESIGN;
674 else
675 THROW_UNKNOWN_PARAMETER_IO_ERROR( unit, wxT( "UNITS" ) );
676
677 return UNITS();
678}
679
680
682{
683 wxASSERT( aNode->GetName() == wxT( "ANGUNITS" ) );
684
685 wxString angUnitStr = GetXmlAttributeIDString( aNode, 0 );
686
687 if( angUnitStr == wxT( "DEGREES" ) )
688 return ANGUNITS::DEGREES;
689 else if( angUnitStr == wxT( "RADIANS" ) )
690 return ANGUNITS::RADIANS;
691 else
692 THROW_UNKNOWN_PARAMETER_IO_ERROR( angUnitStr, aNode->GetName() );
693
694 return ANGUNITS();
695}
696
697
699{
700 wxString aNodeName = aNode->GetName();
701
702 if( aNodeName == wxT( "FRACTIONALGRID" ) || aNodeName == wxT( "STEPGRID" ) )
703 return true;
704 else
705 return false;
706}
707
708
710{
711 wxASSERT( IsGrid( aNode ) );
712
713 wxString aNodeName = aNode->GetName();
714
715 if( aNodeName == wxT( "FRACTIONALGRID" ) )
717 else if( aNodeName == wxT( "STEPGRID" ) )
718 Type = GRID_TYPE::STEPGRID;
719 else
720 wxASSERT_MSG( true, wxT( "Unknown Grid Type" ) );
721
722 Name = GetXmlAttributeIDString( aNode, 0 );
723 Param1 = GetXmlAttributeIDLong( aNode, 1 );
724 Param2 = GetXmlAttributeIDLong( aNode, 2 );
725}
726
727
729{
730 wxASSERT( aNode->GetName() == wxT( "GRIDS" ) );
731
732 XNODE* cNode = aNode->GetChildren();
733
734 for( ; cNode; cNode = cNode->GetNext() )
735 {
736 wxString cNodeName = cNode->GetName();
737
738 if( cNodeName == wxT( "WORKINGGRID" ) )
739 {
740 XNODE* workingGridNode = cNode->GetChildren();
741
742 if( !GRID::IsGrid( workingGridNode ) )
743 {
745 workingGridNode->GetName(), wxT( "GRIDS -> WORKINGGRID" ) );
746 }
747 else
748 {
749 WorkingGrid.Parse( workingGridNode, aContext );
750 }
751 }
752 else if( cNodeName == wxT( "SCREENGRID" ) )
753 {
754 XNODE* screenGridNode = cNode->GetChildren();
755
756 if( !GRID::IsGrid( screenGridNode ) )
757 {
759 screenGridNode->GetName(), wxT( "GRIDS -> SCREENGRID" ) );
760 }
761 else
762 {
763 ScreenGrid.Parse( screenGridNode, aContext );
764 }
765 }
766 else if( GRID::IsGrid( cNode ) )
767 {
768 GRID userGrid;
769 userGrid.Parse( cNode, aContext );
770 UserGrids.push_back( userGrid );
771 }
772 }
773}
774
775
777{
778 wxString cNodeName = aChildNode->GetName();
779
780 if( cNodeName == wxT( "UNITS" ) )
781 {
782 Units = ParseUnits( aChildNode );
783 }
784 else if( cNodeName == wxT( "UNITSPRECISION" ) )
785 {
786 UnitDisplPrecision = GetXmlAttributeIDLong( aChildNode, 0 );
787 }
788 else if( cNodeName == wxT( "INTERLINEGAP" ) )
789 {
790 InterlineGap = GetXmlAttributeIDLong( aChildNode, 0 );
791 }
792 else if( cNodeName == wxT( "BARLINEGAP" ) )
793 {
794 BarlineGap = GetXmlAttributeIDLong( aChildNode, 0 );
795 }
796 else if( cNodeName == wxT( "ALLOWBARTEXT" ) )
797 {
798 AllowBarredText = true;
799 }
800 else if( cNodeName == wxT( "ANGULARPRECISION" ) )
801 {
802 AngularPrecision = GetXmlAttributeIDLong( aChildNode, 0 );
803 }
804 else if( cNodeName == wxT( "DESIGNORIGIN" ) )
805 {
806 DesignOrigin.Parse( aChildNode->GetChildren(), aContext );
807 }
808 else if( cNodeName == wxT( "DESIGNAREA" ) )
809 {
810 std::vector<POINT> pts = ParseAllChildPoints( aChildNode, aContext, true, 2 );
811 DesignArea = std::make_pair( pts[0], pts[1] );
812 }
813 else if( cNodeName == wxT( "DESIGNREF" ) )
814 {
815 DesignOrigin.Parse( aChildNode->GetChildren(), aContext );
816 }
817 else if( cNodeName == wxT( "DESIGNLIMIT" ) )
818 {
819 DesignLimit.Parse( aChildNode->GetChildren(), aContext );
820 }
821 else if( cNodeName == wxT( "PINNOOFFSET" ) )
822 {
823 PinNoOffset = GetXmlAttributeIDLong( aChildNode, 0 );
824 }
825 else if( cNodeName == wxT( "PINNOANGLE" ) )
826 {
827 PinNoAngle = GetXmlAttributeIDLong( aChildNode, 0 );
828 }
829 else
830 {
831 return false;
832 }
833
834 return true;
835}
836
837
839{
840 wxASSERT( aNode->GetName() == wxT( "SETTINGS" ) );
841
842 XNODE* cNode = aNode->GetChildren();
843
844 for( ; cNode; cNode = cNode->GetNext() )
845 {
846 wxString cNodeName = cNode->GetName();
847
848 if( ParseSubNode( cNode, aContext ) )
849 continue;
850 else
851 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "SETTINGS" ) );
852 }
853}
854
855
856wxString CADSTAR_ARCHIVE_PARSER::ParseTextFields( const wxString& aTextString,
857 PARSER_CONTEXT* aContext )
858{
859 static const std::map<TEXT_FIELD_NAME, wxString> txtTokens =
860 {
861 { TEXT_FIELD_NAME::DESIGN_TITLE, wxT( "DESIGN TITLE" ) },
862 { TEXT_FIELD_NAME::SHORT_JOBNAME, wxT( "SHORT_JOBNAME" ) },
863 { TEXT_FIELD_NAME::LONG_JOBNAME, wxT( "LONG_JOBNAME" ) },
864 { TEXT_FIELD_NAME::NUM_OF_SHEETS, wxT( "NUM_OF_SHEETS" ) },
865 { TEXT_FIELD_NAME::SHEET_NUMBER, wxT( "SHEET_NUMBER" ) },
866 { TEXT_FIELD_NAME::SHEET_NAME, wxT( "SHEET_NAME" ) },
867 { TEXT_FIELD_NAME::VARIANT_NAME, wxT( "VARIANT_NAME" ) },
868 { TEXT_FIELD_NAME::VARIANT_DESCRIPTION, wxT( "VARIANT_DESCRIPTION" ) },
869 { TEXT_FIELD_NAME::REG_USER, wxT( "REG_USER" ) },
870 { TEXT_FIELD_NAME::COMPANY_NAME, wxT( "COMPANY_NAME" ) },
871 { TEXT_FIELD_NAME::CURRENT_USER, wxT( "CURRENT_USER" ) },
872 { TEXT_FIELD_NAME::DATE, wxT( "DATE" ) },
873 { TEXT_FIELD_NAME::TIME, wxT( "TIME" ) },
874 { TEXT_FIELD_NAME::MACHINE_NAME, wxT( "MACHINE_NAME" ) },
875 { TEXT_FIELD_NAME::FROM_FILE, wxT( "FROM_FILE" ) },
876 { TEXT_FIELD_NAME::DISTANCE, wxT( "DISTANCE" ) },
877 { TEXT_FIELD_NAME::UNITS_SHORT, wxT( "UNITS SHORT" ) },
878 { TEXT_FIELD_NAME::UNITS_ABBREV, wxT( "UNITS ABBREV" ) },
879 { TEXT_FIELD_NAME::UNITS_FULL, wxT( "UNITS FULL" ) },
880 { TEXT_FIELD_NAME::HYPERLINK, wxT( "HYPERLINK" ) }
881 };
882
883 wxString remainingStr = aTextString;
884 wxString returnStr;
885
886 while( remainingStr.size() > 0 )
887 {
888 //Find the start token
889 size_t startpos = remainingStr.Find( wxT( "<@" ) );
890
891 if( static_cast<int>( startpos ) == wxNOT_FOUND )
892 {
893 // No more fields to parse, add to return string
894 returnStr += remainingStr;
895 break;
896 }
897
898 if( startpos > 0 )
899 returnStr += remainingStr.SubString( 0, startpos - 1 );
900
901 if( ( startpos + 2 ) >= remainingStr.size() )
902 break;
903
904 remainingStr = remainingStr.Mid( startpos + 2 );
905
906 //Find the expected token for the field
908
909 for( std::pair<TEXT_FIELD_NAME, wxString> txtF : txtTokens )
910 {
911 if( remainingStr.StartsWith( txtF.second ) )
912 {
913 foundField = txtF.first;
914 break;
915 }
916 }
917
918 if( foundField == TEXT_FIELD_NAME::NONE )
919 {
920 // Not a valid field, lets keep looking
921 returnStr += wxT( "<@" );
922 continue;
923 }
924
925 //Now lets find the end token
926 size_t endpos = remainingStr.Find( wxT( "@>" ) );
927
928 if( static_cast<int>( endpos ) == wxNOT_FOUND )
929 {
930 // The field we found isn't valid as it doesn't have a termination
931 // Lets append the whole thing as plain text
932 returnStr += wxT( "<@" ) + remainingStr;
933 break;
934 }
935
936 size_t valueStart = txtTokens.at( foundField ).size();
937 wxString fieldValue = remainingStr.SubString( valueStart, endpos - 1 );
938 wxString address;
939
940 if( foundField == TEXT_FIELD_NAME::FROM_FILE || foundField == TEXT_FIELD_NAME::HYPERLINK )
941 {
942 // The first character should always be a double quotation mark
943 wxASSERT_MSG( fieldValue.at( 0 ) == '"', "Expected '\"' as the first character" );
944
945 size_t splitPos = fieldValue.find_first_of( '"', 1 );
946 address = fieldValue.SubString( 1, splitPos - 1 );
947
948 if( foundField == TEXT_FIELD_NAME::HYPERLINK )
949 {
950 // Assume the last two characters are "@>"
951 wxASSERT_MSG( remainingStr.EndsWith( wxT( "@>" ) ),
952 "Expected '@>' at the end of a hyperlink" );
953
954 fieldValue = remainingStr.SubString( valueStart + splitPos + 1,
955 remainingStr.Length() - 3 );
956
957 remainingStr = wxEmptyString;
958 }
959 else
960 {
961 fieldValue = fieldValue.Mid( splitPos + 1 );
962 }
963 }
964
965 switch( foundField )
966 {
978
979 if( aContext->TextFieldToValuesMap.find( foundField )
980 != aContext->TextFieldToValuesMap.end() )
981 {
982 aContext->InconsistentTextFields.insert( foundField );
983 }
984 else
985 {
986 aContext->TextFieldToValuesMap.insert( { foundField, fieldValue } );
987 }
988
990
994 returnStr += wxT( "${" ) + CADSTAR_TO_KICAD_FIELDS.at( foundField ) + wxT( "}" );
995 break;
996
1001 // Just flatten the text for distances
1002 returnStr += fieldValue;
1003 break;
1004
1006 {
1007 wxFileName fn( address );
1008 wxString fieldFmt = wxT( "FROM_FILE_%s_%s" );
1009 wxString fieldName = wxString::Format( fieldFmt, fn.GetName(), fn.GetExt() );
1010
1011 int version = 1;
1012
1013 while(
1014 aContext->FilenamesToTextMap.find( fieldName )
1015 != aContext->FilenamesToTextMap.end()
1016 && aContext->FilenamesToTextMap.at( fieldName ) != fieldValue )
1017 {
1018 fieldName = wxString::Format( fieldFmt, fn.GetName(), fn.GetExt() )
1019 + wxString::Format( wxT( "_%d" ), version++ );
1020 }
1021
1022 aContext->FilenamesToTextMap[fieldName] = fieldValue;
1023 returnStr += wxT( "${" ) + fieldName + wxT( "}" );
1024 }
1025 break;
1026
1028 {
1029 aContext->TextToHyperlinksMap[fieldValue] = address;
1030 returnStr += ParseTextFields( fieldValue, aContext );
1031 }
1032 break;
1033
1035 wxFAIL_MSG( "We should have already covered this scenario above" );
1036 break;
1037 }
1038
1039
1040 if( ( endpos + 2 ) >= remainingStr.size() )
1041 break;
1042
1043 remainingStr = remainingStr.Mid( endpos + 2 );
1044 }
1045
1046 return returnStr;
1047}
1048
1049
1051{
1052 wxASSERT( aNode->GetName() == wxT( "ALIGN" ) );
1053
1054 wxString alignmentStr = GetXmlAttributeIDString( aNode, 0 );
1055
1056 if( alignmentStr == wxT( "BOTTOMCENTER" ) )
1058 else if( alignmentStr == wxT( "BOTTOMLEFT" ) )
1059 return ALIGNMENT::BOTTOMLEFT;
1060 else if( alignmentStr == wxT( "BOTTOMRIGHT" ) )
1062 else if( alignmentStr == wxT( "CENTERCENTER" ) )
1064 else if( alignmentStr == wxT( "CENTERLEFT" ) )
1065 return ALIGNMENT::CENTERLEFT;
1066 else if( alignmentStr == wxT( "CENTERRIGHT" ) )
1068 else if( alignmentStr == wxT( "TOPCENTER" ) )
1069 return ALIGNMENT::TOPCENTER;
1070 else if( alignmentStr == wxT( "TOPLEFT" ) )
1071 return ALIGNMENT::TOPLEFT;
1072 else if( alignmentStr == wxT( "TOPRIGHT" ) )
1073 return ALIGNMENT::TOPRIGHT;
1074 else
1075 THROW_UNKNOWN_PARAMETER_IO_ERROR( alignmentStr, wxT( "ALIGN" ) );
1076
1077 //shouldn't be here but avoids compiler warning
1079}
1080
1081
1083{
1084 wxASSERT( aNode->GetName() == wxT( "JUSTIFICATION" ) );
1085
1086 wxString justificationStr = GetXmlAttributeIDString( aNode, 0 );
1087
1088 if( justificationStr == wxT( "LEFT" ) )
1089 return JUSTIFICATION::LEFT;
1090 else if( justificationStr == wxT( "RIGHT" ) )
1091 return JUSTIFICATION::RIGHT;
1092 else if( justificationStr == wxT( "CENTER" ) )
1093 return JUSTIFICATION::CENTER;
1094 else
1095 THROW_UNKNOWN_PARAMETER_IO_ERROR( justificationStr, wxT( "JUSTIFICATION" ) );
1096
1097 return JUSTIFICATION::LEFT;
1098}
1099
1100
1102{
1103 wxASSERT( aNode->GetName() == wxT( "READABILITY" ) );
1104
1105 wxString readabilityStr = GetXmlAttributeIDString( aNode, 0 );
1106
1107 if( readabilityStr == wxT( "BOTTOM_TO_TOP" ) )
1109 else if( readabilityStr == wxT( "TOP_TO_BOTTOM" ) )
1111 else
1112 THROW_UNKNOWN_PARAMETER_IO_ERROR( readabilityStr, wxT( "READABILITY" ) );
1113
1115}
1116
1117
1119 PARSER_CONTEXT* aContext )
1120{
1121 TextCodeID = GetXmlAttributeIDString( aNode, 0 );
1122 LayerID = GetXmlAttributeIDString( aNode, 1 );
1123}
1124
1125
1127 PARSER_CONTEXT* aContext )
1128{
1129 wxString cNodeName = aChildNode->GetName();
1130
1131 if( cNodeName == wxT( "PT" ) )
1132 Position.Parse( aChildNode, aContext );
1133 else if( cNodeName == wxT( "ORIENT" ) )
1134 OrientAngle = GetXmlAttributeIDLong( aChildNode, 0 );
1135 else if( cNodeName == wxT( "MIRROR" ) )
1136 Mirror = true;
1137 else if( cNodeName == wxT( "FIX" ) )
1138 Fixed = true;
1139 else if( cNodeName == wxT( "ALIGN" ) )
1140 Alignment = ParseAlignment( aChildNode );
1141 else if( cNodeName == wxT( "JUSTIFICATION" ) )
1142 Justification = ParseJustification( aChildNode );
1143 else
1144 return false;
1145
1146 return true;
1147}
1148
1149
1151{
1152 wxASSERT( aNode->GetName() == wxT( "ATTRLOC" ) );
1153
1154 ParseIdentifiers( aNode, aContext );
1155
1156 //Parse child nodes
1157 XNODE* cNode = aNode->GetChildren();
1158
1159 for( ; cNode; cNode = cNode->GetNext() )
1160 {
1161 if( ParseSubNode( cNode, aContext ) )
1162 continue;
1163 else
1164 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "ATTRLOC" ) );
1165 }
1166
1167 if( Position.x == UNDEFINED_VALUE || Position.y == UNDEFINED_VALUE )
1168 THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "ATTRLOC" ) );
1169}
1170
1171
1173{
1174 wxASSERT( aNode->GetName() == wxT( "COLUMNORDER" ) );
1175
1176 ID = GetXmlAttributeIDLong( aNode, 0 );
1177 Order = GetXmlAttributeIDLong( aNode, 1 );
1178
1179 CheckNoChildNodes( aNode );
1180}
1181
1182
1184{
1185 wxASSERT( aNode->GetName() == wxT( "COLUMNWIDTH" ) );
1186
1187 ID = GetXmlAttributeIDLong( aNode, 0 );
1188 Width = GetXmlAttributeIDLong( aNode, 1 );
1189
1190 CheckNoChildNodes( aNode );
1191}
1192
1193
1195{
1196 wxASSERT( aNode->GetName() == wxT( "ATTRNAME" ) );
1197
1198 ID = GetXmlAttributeIDString( aNode, 0 );
1199 Name = GetXmlAttributeIDString( aNode, 1 );
1200
1201 XNODE* cNode = aNode->GetChildren();
1202 wxString location = wxString::Format( "ATTRNAME -> %s", Name );
1203
1204 for( ; cNode; cNode = cNode->GetNext() )
1205 {
1206 wxString cNodeName = cNode->GetName();
1207
1208 if( cNodeName == wxT( "ATTROWNER" ) )
1209 {
1210 wxString attOwnerVal = GetXmlAttributeIDString( cNode, 0 );
1211
1212 if( attOwnerVal == wxT( "ALL_ITEMS" ) )
1213 AttributeOwner = ATTROWNER::ALL_ITEMS;
1214 else if( attOwnerVal == wxT( "AREA" ) )
1215 AttributeOwner = ATTROWNER::AREA;
1216 else if( attOwnerVal == wxT( "BOARD" ) )
1217 AttributeOwner = ATTROWNER::BOARD;
1218 else if( attOwnerVal == wxT( "COMPONENT" ) )
1219 AttributeOwner = ATTROWNER::COMPONENT;
1220 else if( attOwnerVal == wxT( "CONNECTION" ) )
1221 AttributeOwner = ATTROWNER::CONNECTION;
1222 else if( attOwnerVal == wxT( "COPPER" ) )
1223 AttributeOwner = ATTROWNER::COPPER;
1224 else if( attOwnerVal == wxT( "DOCSYMBOL" ) )
1225 AttributeOwner = ATTROWNER::DOCSYMBOL;
1226 else if( attOwnerVal == wxT( "FIGURE" ) )
1227 AttributeOwner = ATTROWNER::FIGURE;
1228 else if( attOwnerVal == wxT( "NET" ) )
1229 AttributeOwner = ATTROWNER::NET;
1230 else if( attOwnerVal == wxT( "NETCLASS" ) )
1231 AttributeOwner = ATTROWNER::NETCLASS;
1232 else if( attOwnerVal == wxT( "PART" ) )
1233 AttributeOwner = ATTROWNER::PART;
1234 else if( attOwnerVal == wxT( "PART_DEFINITION" ) )
1235 AttributeOwner = ATTROWNER::PART_DEFINITION;
1236 else if( attOwnerVal == wxT( "PIN" ) )
1237 AttributeOwner = ATTROWNER::PIN;
1238 else if( attOwnerVal == wxT( "SIGNALREF" ) )
1239 AttributeOwner = ATTROWNER::SIGNALREF;
1240 else if( attOwnerVal == wxT( "SYMBOL" ) )
1241 AttributeOwner = ATTROWNER::SYMBOL;
1242 else if( attOwnerVal == wxT( "SYMDEF" ) )
1243 AttributeOwner = ATTROWNER::SYMDEF;
1244 else if( attOwnerVal == wxT( "TEMPLATE" ) )
1245 AttributeOwner = ATTROWNER::TEMPLATE;
1246 else if( attOwnerVal == wxT( "TESTPOINT" ) )
1247 AttributeOwner = ATTROWNER::TESTPOINT;
1248 else
1249 THROW_UNKNOWN_PARAMETER_IO_ERROR( attOwnerVal, location );
1250 }
1251 else if( cNodeName == wxT( "ATTRUSAGE" ) )
1252 {
1253 wxString attUsageVal = GetXmlAttributeIDString( cNode, 0 );
1254
1255 if( attUsageVal == wxT( "BOTH" ) )
1256 AttributeUsage = ATTRUSAGE::BOTH;
1257 else if( attUsageVal == wxT( "COMPONENT" ) )
1258 AttributeUsage = ATTRUSAGE::COMPONENT;
1259 else if( attUsageVal == wxT( "PART_DEFINITION" ) )
1260 AttributeUsage = ATTRUSAGE::PART_DEFINITION;
1261 else if( attUsageVal == wxT( "PART_LIBRARY" ) )
1262 AttributeUsage = ATTRUSAGE::PART_LIBRARY;
1263 else if( attUsageVal == wxT( "SYMBOL" ) )
1264 AttributeUsage = ATTRUSAGE::SYMBOL;
1265 else
1266 THROW_UNKNOWN_PARAMETER_IO_ERROR( attUsageVal, location );
1267 }
1268 else if( cNodeName == wxT( "NOTRANSFER" ) )
1269 {
1270 NoTransfer = true;
1271 }
1272 else if( cNodeName == wxT( "COLUMNORDER" ) )
1273 {
1274 COLUMNORDER cOrder;
1275 cOrder.Parse( cNode, aContext );
1276 ColumnOrders.push_back( cOrder );
1277 }
1278 else if( cNodeName == wxT( "COLUMNWIDTH" ) )
1279 {
1280 COLUMNWIDTH cWidth;
1281 cWidth.Parse( cNode, aContext );
1282 ColumnWidths.push_back( cWidth );
1283 }
1284 else if( cNodeName == wxT( "COLUMNINVISIBLE" ) )
1285 {
1286 ColumnInvisible = true;
1287 }
1288 else
1289 {
1290 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location );
1291 }
1292 }
1293}
1294
1295
1297{
1298 wxASSERT( aNode->GetName() == wxT( "ATTR" ) );
1299
1300 AttributeID = GetXmlAttributeIDString( aNode, 0 );
1301 Value = GetXmlAttributeIDString( aNode, 1 );
1302
1303 XNODE* cNode = aNode->GetChildren();
1304
1305 for( ; cNode; cNode = cNode->GetNext() )
1306 {
1307 if( cNode->GetName() == wxT( "READONLY" ) )
1308 {
1309 ReadOnly = true;
1310 }
1311 else if( cNode->GetName() == wxT( "ATTRLOC" ) )
1312 {
1313 AttributeLocation.Parse( cNode, aContext );
1314 HasLocation = true;
1315 }
1316 else
1317 {
1318 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "ATTR" ) );
1319 }
1320 }
1321}
1322
1323
1325{
1326 wxASSERT( aNode->GetName() == wxT( "TEXTLOC" ) );
1327
1328 wxString attributeStr = GetXmlAttributeIDString( aNode, 0 );
1329 bool attributeIDisSet = false;
1330
1331 if( attributeStr == wxT( "PART_NAME" ) )
1332 {
1333 AttributeID = PART_NAME_ATTRID;
1334 attributeIDisSet = true;
1335 }
1336 else if( attributeStr == wxT( "COMP_NAME" ) )
1337 {
1338 AttributeID = COMPONENT_NAME_ATTRID;
1339 attributeIDisSet = true;
1340 }
1341 else if( attributeStr == wxT( "COMP_NAME2" ) )
1342 {
1343 AttributeID = COMPONENT_NAME_2_ATTRID;
1344 attributeIDisSet = true;
1345 }
1346 else if( attributeStr == wxT( "SYMBOL_NAME" ) )
1347 {
1348 AttributeID = SYMBOL_NAME_ATTRID;
1349 attributeIDisSet = true;
1350 }
1351 else if( attributeStr == wxT( "LINK_ORIGIN" ) )
1352 {
1353 AttributeID = LINK_ORIGIN_ATTRID;
1354 attributeIDisSet = true;
1355 }
1356 else if( attributeStr == wxT( "SIGNALNAME_ORIGIN" ) )
1357 {
1358 AttributeID = SIGNALNAME_ORIGIN_ATTRID;
1359 attributeIDisSet = true;
1360 }
1361 else if( attributeStr == wxT( "ATTRREF" ) )
1362 {
1363 //We will initialise when we parse all child nodes
1364 attributeIDisSet = false;
1365 }
1366 else
1367 {
1368 THROW_UNKNOWN_PARAMETER_IO_ERROR( attributeStr, wxT( "TEXTLOC" ) );
1369 }
1370
1371 TextCodeID = GetXmlAttributeIDString( aNode, 1 );
1372 LayerID = GetXmlAttributeIDString( aNode, 2, false );
1373
1374 //Parse child nodes
1375 XNODE* cNode = aNode->GetChildren();
1376
1377 for( ; cNode; cNode = cNode->GetNext() )
1378 {
1379 wxString cNodeName = cNode->GetName();
1380
1381 if( ParseSubNode( cNode, aContext ) )
1382 {
1383 continue;
1384 }
1385 else if( !attributeIDisSet && cNodeName == wxT( "ATTRREF" ) )
1386 {
1387 AttributeID = GetXmlAttributeIDString( cNode, 0 );
1388 attributeIDisSet = true;
1389 }
1390 else if( cNodeName == wxT( "ORIENT" ) )
1391 {
1392 OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
1393 }
1394 else if( cNodeName == wxT( "MIRROR" ) )
1395 {
1396 Mirror = true;
1397 }
1398 else if( cNodeName == wxT( "FIX" ) )
1399 {
1400 Fixed = true;
1401 }
1402 else if( cNodeName == wxT( "ALIGN" ) )
1403 {
1404 Alignment = ParseAlignment( cNode );
1405 }
1406 else if( cNodeName == wxT( "JUSTIFICATION" ) )
1407 {
1408 Justification = ParseJustification( cNode );
1409 }
1410 else
1411 {
1412 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "TEXTLOC" ) );
1413 }
1414 }
1415
1416 if( Position.x == UNDEFINED_VALUE || Position.y == UNDEFINED_VALUE )
1417 THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "TEXTLOC" ) );
1418}
1419
1420
1422{
1423 wxASSERT( aNode->GetName() == wxT( "NETCLASS" ) );
1424
1425 ID = GetXmlAttributeIDString( aNode, 0 );
1426 Name = GetXmlAttributeIDString( aNode, 1 );
1427
1428 XNODE* cNode = aNode->GetChildren();
1429 wxString location = wxString::Format( "NETCLASS -> %s", Name );
1430
1431 for( ; cNode; cNode = cNode->GetNext() )
1432 {
1433 wxString cNodeName = cNode->GetName();
1434
1435 if( cNodeName == wxT( "ATTR" ) )
1436 {
1437 ATTRIBUTE_VALUE attribute_val;
1438 attribute_val.Parse( cNode, aContext );
1439 Attributes.push_back( attribute_val );
1440 }
1441 else
1442 {
1443 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location );
1444 }
1445 }
1446}
1447
1448
1450{
1451 wxASSERT( aNode->GetName() == wxT( "SPCCLASSNAME" ) );
1452
1453 ID = GetXmlAttributeIDString( aNode, 0 );
1454 Name = GetXmlAttributeIDString( aNode, 1 );
1455}
1456
1457
1459{
1460 wxString nodeName = aChildNode->GetName();
1461
1462 if( nodeName == wxT( "LINECODE" ) )
1463 {
1464 LINECODE linecode;
1465 linecode.Parse( aChildNode, aContext );
1466 LineCodes.insert( std::make_pair( linecode.ID, linecode ) );
1467 }
1468 else if( nodeName == wxT( "HATCHCODE" ) )
1469 {
1470 HATCHCODE hatchcode;
1471 hatchcode.Parse( aChildNode, aContext );
1472 HatchCodes.insert( std::make_pair( hatchcode.ID, hatchcode ) );
1473 }
1474 else if( nodeName == wxT( "TEXTCODE" ) )
1475 {
1476 TEXTCODE textcode;
1477 textcode.Parse( aChildNode, aContext );
1478 TextCodes.insert( std::make_pair( textcode.ID, textcode ) );
1479 }
1480 else if( nodeName == wxT( "ROUTECODE" ) )
1481 {
1482 ROUTECODE routecode;
1483 routecode.Parse( aChildNode, aContext );
1484 RouteCodes.insert( std::make_pair( routecode.ID, routecode ) );
1485 }
1486 else if( nodeName == wxT( "ATTRNAME" ) )
1487 {
1488 ATTRNAME attrname;
1489 attrname.Parse( aChildNode, aContext );
1490 AttributeNames.insert( std::make_pair( attrname.ID, attrname ) );
1491 }
1492 else if( nodeName == wxT( "NETCLASS" ) )
1493 {
1494 CADSTAR_NETCLASS netclass;
1495 netclass.Parse( aChildNode, aContext );
1496 NetClasses.insert( std::make_pair( netclass.ID, netclass ) );
1497 }
1498 else if( nodeName == wxT( "SPCCLASSNAME" ) )
1499 {
1500 SPCCLASSNAME spcclassname;
1501 spcclassname.Parse( aChildNode, aContext );
1502 SpacingClassNames.insert( std::make_pair( spcclassname.ID, spcclassname ) );
1503 }
1504 else
1505 {
1506 return false;
1507 }
1508
1509 return true;
1510}
1511
1512
1514{
1515 wxASSERT( aNode->GetName() == wxT( "SWAPRULE" ) );
1516
1517 SWAP_RULE retval;
1518 wxString swapRuleStr = GetXmlAttributeIDString( aNode, 0 );
1519
1520 if( swapRuleStr == wxT( "NO_SWAP" ) )
1521 retval = SWAP_RULE::NO_SWAP;
1522 else if( swapRuleStr == wxT( "USE_SWAP_LAYER" ) )
1524 else
1525 THROW_UNKNOWN_PARAMETER_IO_ERROR( swapRuleStr, wxT( "SWAPRULE" ) );
1526
1527 return retval;
1528}
1529
1530
1532{
1533 wxASSERT( aNode->GetName() == wxT( "REUSEBLOCK" ) );
1534
1535 ID = GetXmlAttributeIDString( aNode, 0 );
1536 Name = GetXmlAttributeIDString( aNode, 1 );
1537 FileName = GetXmlAttributeIDString( aNode, 2 );
1538
1539 XNODE* cNode = aNode->GetChildren();
1540
1541 for( ; cNode; cNode = cNode->GetNext() )
1542 {
1543 wxString cNodeName = cNode->GetName();
1544
1545 if( cNodeName == wxT( "MIRROR" ) )
1546 Mirror = true;
1547 else if( cNodeName == wxT( "ORIENT" ) )
1548 OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
1549 else
1550 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "REUSEBLOCK" ) );
1551 }
1552}
1553
1554
1556{
1557 return ReuseBlockID == wxEmptyString && ItemReference == wxEmptyString;
1558}
1559
1560
1562{
1563 wxASSERT( aNode->GetName() == wxT( "REUSEBLOCKREF" ) );
1564
1565 ReuseBlockID = GetXmlAttributeIDString( aNode, 0 );
1566 ItemReference = GetXmlAttributeIDString( aNode, 1 );
1567
1568 CheckNoChildNodes( aNode );
1569}
1570
1571
1573{
1574 wxASSERT( aNode->GetName() == wxT( "GROUP" ) );
1575
1576 ID = GetXmlAttributeIDString( aNode, 0 );
1577 Name = GetXmlAttributeIDString( aNode, 1 );
1578
1579 XNODE* cNode = aNode->GetChildren();
1580
1581 for( ; cNode; cNode = cNode->GetNext() )
1582 {
1583 wxString cNodeName = cNode->GetName();
1584
1585 if( cNodeName == wxT( "FIX" ) )
1586 Fixed = true;
1587 else if( cNodeName == wxT( "TRANSFER" ) )
1588 Transfer = true;
1589 else if( cNodeName == wxT( "GROUPREF" ) )
1590 GroupID = GetXmlAttributeIDString( cNode, 0 );
1591 else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
1592 ReuseBlockRef.Parse( cNode, aContext );
1593 else
1594 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "GROUP" ) );
1595 }
1596}
1597
1598
1600{
1601 wxASSERT( aNode->GetName() == wxT( "FIGURE" ) );
1602
1603 ID = GetXmlAttributeIDString( aNode, 0 );
1604 LineCodeID = GetXmlAttributeIDString( aNode, 1 );
1605 LayerID = GetXmlAttributeIDString( aNode, 2 );
1606
1607 XNODE* cNode = aNode->GetChildren();
1608 bool shapeIsInitialised = false; // Stop more than one Shape Object
1609 wxString location = wxString::Format( "Figure %s", ID );
1610
1611 if( !cNode )
1612 THROW_MISSING_NODE_IO_ERROR( wxT( "Shape" ), location );
1613
1614 for( ; cNode; cNode = cNode->GetNext() )
1615 {
1616 wxString cNodeName = cNode->GetName();
1617
1618 if( !shapeIsInitialised && Shape.IsShape( cNode ) )
1619 {
1620 Shape.Parse( cNode, aContext );
1621 shapeIsInitialised = true;
1622 }
1623 else if( cNodeName == wxT( "SWAPRULE" ) )
1624 {
1625 SwapRule = ParseSwapRule( cNode );
1626 }
1627 else if( cNodeName == wxT( "FIX" ) )
1628 {
1629 Fixed = true;
1630 }
1631 else if( cNodeName == wxT( "GROUPREF" ) )
1632 {
1633
1634 GroupID = GetXmlAttributeIDString( cNode, 0 );
1635 }
1636 else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
1637 {
1638 ReuseBlockRef.Parse( cNode, aContext );
1639 }
1640 else if( cNodeName == wxT( "ATTR" ) )
1641 {
1642 ATTRIBUTE_VALUE attr;
1643 attr.Parse( cNode, aContext );
1644 AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
1645 }
1646 else
1647 {
1648 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, location );
1649 }
1650 }
1651}
1652
1653
1655{
1656 Parse( aNode, aContext, true );
1657}
1658
1659
1661 bool aParseFields )
1662{
1663 wxASSERT( aNode->GetName() == wxT( "TEXT" ) );
1664
1665 ID = GetXmlAttributeIDString( aNode, 0 );
1666 Text = GetXmlAttributeIDString( aNode, 1 );
1667
1668 if( aParseFields )
1669 Text = ParseTextFields( Text, aContext );
1670
1671 TextCodeID = GetXmlAttributeIDString( aNode, 2 );
1672 LayerID = GetXmlAttributeIDString( aNode, 3 );
1673
1674 XNODE* cNode = aNode->GetChildren();
1675
1676 if( !cNode )
1677 THROW_MISSING_NODE_IO_ERROR( wxT( "PT" ), wxT( "TEXT" ) );
1678
1679 for( ; cNode; cNode = cNode->GetNext() )
1680 {
1681 wxString cNodeName = cNode->GetName();
1682
1683 if( cNodeName == wxT( "PT" ) )
1684 Position.Parse( cNode, aContext );
1685 else if( cNodeName == wxT( "ORIENT" ) )
1686 OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
1687 else if( cNodeName == wxT( "MIRROR" ) )
1688 Mirror = true;
1689 else if( cNodeName == wxT( "FIX" ) )
1690 Fixed = true;
1691 else if( cNodeName == wxT( "SWAPRULE" ) )
1692 SwapRule = ParseSwapRule( cNode );
1693 else if( cNodeName == wxT( "ALIGN" ) )
1694 Alignment = ParseAlignment( cNode );
1695 else if( cNodeName == wxT( "JUSTIFICATION" ) )
1696 Justification = ParseJustification( cNode );
1697 else if( cNodeName == wxT( "GROUPREF" ) )
1698 GroupID = GetXmlAttributeIDString( cNode, 0 );
1699 else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
1700 ReuseBlockRef.Parse( cNode, aContext );
1701 else
1702 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxT( "TEXT" ) );
1703 }
1704}
1705
1706
1708{
1709 return generateLibName( ReferenceName, Alternate );
1710}
1711
1712
1714{
1715 wxASSERT( aNode->GetName() == wxT( "SYMDEF" ) );
1716
1717 ID = GetXmlAttributeIDString( aNode, 0 );
1718 ReferenceName = GetXmlAttributeIDString( aNode, 1 );
1719 Alternate = GetXmlAttributeIDString( aNode, 2 );
1720}
1721
1722
1724{
1725 wxString cNodeName = aChildNode->GetName();
1726
1727 if( cNodeName == wxT( "PT" ) )
1728 {
1729 Origin.Parse( aChildNode, aContext );
1730 }
1731 else if( cNodeName == wxT( "STUB" ) )
1732 {
1733 Stub = true;
1734 }
1735 else if( cNodeName == wxT( "VERSION" ) )
1736 {
1737 Version = GetXmlAttributeIDLong( aChildNode, 0 );
1738 }
1739 else if( cNodeName == wxT( "FIGURE" ) )
1740 {
1741 FIGURE figure;
1742 figure.Parse( aChildNode, aContext );
1743 Figures.insert( std::make_pair( figure.ID, figure ) );
1744 }
1745 else if( cNodeName == wxT( "TEXT" ) )
1746 {
1747 TEXT txt;
1748 txt.Parse( aChildNode, aContext );
1749 Texts.insert( std::make_pair( txt.ID, txt ) );
1750 }
1751 else if( cNodeName == wxT( "TEXTLOC" ) )
1752 {
1753 TEXT_LOCATION textloc;
1754 textloc.Parse( aChildNode, aContext );
1755 TextLocations.insert( std::make_pair( textloc.AttributeID, textloc ) );
1756 }
1757 else if( cNodeName == wxT( "ATTR" ) )
1758 {
1759 ATTRIBUTE_VALUE attrVal;
1760 attrVal.Parse( aChildNode, aContext );
1761 AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) );
1762 }
1763 else
1764 {
1765 return false;
1766 }
1767
1768 return true;
1769}
1770
1771
1773{
1774 wxASSERT( aNode->GetName() == wxT( "GATEDEFINITION" ) );
1775
1776 ID = GetXmlAttributeIDString( aNode, 0 );
1777 Name = GetXmlAttributeIDString( aNode, 1 );
1778 Alternate = GetXmlAttributeIDString( aNode, 2 );
1779 PinCount = GetXmlAttributeIDLong( aNode, 3 );
1780
1781 CheckNoChildNodes( aNode );
1782}
1783
1784
1786{
1787 wxASSERT( aNode->GetName() == wxT( "PINTYPE" ) );
1788
1789 wxString pinTypeStr = GetXmlAttributeIDString( aNode, 0 );
1790
1791 std::map<wxString, CADSTAR_PIN_TYPE> pinTypeMap = {
1792 { wxT( "INPUT" ), CADSTAR_PIN_TYPE::INPUT },
1793 { wxT( "OUTPUT_OR" ), CADSTAR_PIN_TYPE::OUTPUT_OR },
1794 { wxT( "OUTPUT_NOT_OR" ), CADSTAR_PIN_TYPE::OUTPUT_NOT_OR },
1795 { wxT( "OUTPUT_NOT_NORM_OR" ), CADSTAR_PIN_TYPE::OUTPUT_NOT_NORM_OR },
1796 { wxT( "POWER" ), CADSTAR_PIN_TYPE::POWER },
1797 { wxT( "GROUND" ), CADSTAR_PIN_TYPE::GROUND },
1798 { wxT( "TRISTATE_BIDIR" ), CADSTAR_PIN_TYPE::TRISTATE_BIDIR },
1799 { wxT( "TRISTATE_INPUT" ), CADSTAR_PIN_TYPE::TRISTATE_INPUT },
1800 { wxT( "TRISTATE_DRIVER" ), CADSTAR_PIN_TYPE::TRISTATE_DRIVER } };
1801
1802 if( pinTypeMap.find( pinTypeStr ) == pinTypeMap.end() )
1803 THROW_UNKNOWN_PARAMETER_IO_ERROR( pinTypeStr, aNode->GetName() );
1804
1805 return pinTypeMap[pinTypeStr];
1806}
1807
1808
1810{
1811 wxASSERT( aNode->GetName() == wxT( "PARTDEFINITIONPIN" ) );
1812
1813 ID = GetXmlAttributeIDLong( aNode, 0 );
1814
1815 XNODE* cNode = aNode->GetChildren();
1816
1817 for( ; cNode; cNode = cNode->GetNext() )
1818 {
1819 wxString cNodeName = cNode->GetName();
1820
1821 if( cNodeName == wxT( "PINNAME" ) )
1822 {
1823 Name = GetXmlAttributeIDString( cNode, 0 );
1824 }
1825 else if( cNodeName == wxT( "PINLABEL" ) )
1826 {
1827 Label = GetXmlAttributeIDString( cNode, 0 );
1828 }
1829 else if( cNodeName == wxT( "PINSIGNAL" ) )
1830 {
1831 Signal = GetXmlAttributeIDString( cNode, 0 );
1832 }
1833 else if( cNodeName == wxT( "PINTERM" ) )
1834 {
1835 TerminalGate = GetXmlAttributeIDString( cNode, 0 );
1836 TerminalPin = GetXmlAttributeIDLong( cNode, 1 );
1837 }
1838 else if( cNodeName == wxT( "PINTYPE" ) )
1839 {
1840 Type = GetPinType( cNode );
1841 }
1842 else if( cNodeName == wxT( "PINLOAD" ) )
1843 {
1844 Load = GetXmlAttributeIDLong( cNode, 0 );
1845 }
1846 else if( cNodeName == wxT( "PINPOSITION" ) )
1847 {
1848 Position = CADSTAR_PIN_POSITION( GetXmlAttributeIDLong( cNode, 0 ) );
1849 }
1850 else if( cNodeName == wxT( "PINIDENTIFIER" ) )
1851 {
1852 Identifier = GetXmlAttributeIDString( cNode, 0 );
1853 }
1854 else
1855 {
1856 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
1857 }
1858 }
1859}
1860
1861
1863{
1864 wxASSERT( aNode->GetName() == wxT( "PARTPIN" ) );
1865
1866 ID = GetXmlAttributeIDLong( aNode, 0 );
1867
1868 XNODE* cNode = aNode->GetChildren();
1869
1870 for( ; cNode; cNode = cNode->GetNext() )
1871 {
1872 wxString cNodeName = cNode->GetName();
1873
1874 if( cNodeName == wxT( "PINNAME" ) )
1875 Name = GetXmlAttributeIDString( cNode, 0 );
1876 else if( cNodeName == wxT( "PINTYPE" ) )
1877 Type = GetPinType( cNode );
1878 else if( cNodeName == wxT( "PINIDENTIFIER" ) )
1879 Identifier = GetXmlAttributeIDString( cNode, 0 );
1880 else
1881 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
1882 }
1883}
1884
1885
1887 PARSER_CONTEXT* aContext )
1888{
1889 wxASSERT( aNode->GetName() == wxT( "PINEQUIVALENCE" ) );
1890
1891 wxXmlAttribute* xmlAttribute = aNode->GetAttributes();
1892
1893 for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() )
1894 {
1895 if( !IsValidAttribute( xmlAttribute ) )
1896 continue;
1897
1898 long pinId;
1899
1900 if( !xmlAttribute->GetValue().ToLong( &pinId ) )
1901 THROW_UNKNOWN_PARAMETER_IO_ERROR( xmlAttribute->GetValue(), aNode->GetName() );
1902
1903 PinIDs.push_back( (PART_DEFINITION_PIN_ID) pinId );
1904 }
1905
1906 CheckNoChildNodes( aNode );
1907}
1908
1909
1911 PARSER_CONTEXT* aContext )
1912{
1913 wxASSERT( aNode->GetName() == wxT( "SWAPGATE" ) );
1914
1915 wxXmlAttribute* xmlAttribute = aNode->GetAttributes();
1916
1917 for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() )
1918 {
1919 if( !IsValidAttribute( xmlAttribute ) )
1920 continue;
1921
1922 long pinId;
1923
1924 if( !xmlAttribute->GetValue().ToLong( &pinId ) )
1925 THROW_UNKNOWN_PARAMETER_IO_ERROR( xmlAttribute->GetValue(), aNode->GetName() );
1926
1927 PinIDs.push_back( (PART_DEFINITION_PIN_ID) pinId );
1928 }
1929
1930 CheckNoChildNodes( aNode );
1931}
1932
1933
1935 PARSER_CONTEXT* aContext )
1936{
1937 wxASSERT( aNode->GetName() == wxT( "SWAPGROUP" ) );
1938
1939 GateName = GetXmlAttributeIDString( aNode, 0 );
1940
1941 XNODE* cNode = aNode->GetChildren();
1942
1943 for( ; cNode; cNode = cNode->GetNext() )
1944 {
1945 wxString cNodeName = cNode->GetName();
1946
1947 if( cNodeName == wxT( "EXTERNAL" ) )
1948 {
1949 External = true;
1950 }
1951 else if( cNodeName == wxT( "SWAPGATE" ) )
1952 {
1953 SWAP_GATE swapGate;
1954 swapGate.Parse( cNode, aContext );
1955 SwapGates.push_back( swapGate );
1956 }
1957 else
1958 {
1959 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
1960 }
1961 }
1962}
1963
1964
1966{
1967 wxASSERT( aNode->GetName() == wxT( "PARTDEFINITION" ) );
1968
1969 Name = GetXmlAttributeIDString( aNode, 0 );
1970
1971 XNODE* cNode = aNode->GetChildren();
1972
1973 for( ; cNode; cNode = cNode->GetNext() )
1974 {
1975 wxString cNodeName = cNode->GetName();
1976
1977 if( cNodeName == wxT( "HIDEPINNAMES" ) )
1978 {
1979 HidePinNames = true;
1980 }
1981 else if( cNodeName == wxT( "MAXPIN" ) )
1982 {
1983 MaxPinCount = GetXmlAttributeIDLong( cNode, 0 );
1984 }
1985 else if( cNodeName == wxT( "GATEDEFINITION" ) )
1986 {
1987 GATE gate;
1988 gate.Parse( cNode, aContext );
1989 GateSymbols.insert( std::make_pair( gate.ID, gate ) );
1990 }
1991 else if( cNodeName == wxT( "PARTDEFINITIONPIN" ) )
1992 {
1993 PIN pin;
1994 pin.Parse( cNode, aContext );
1995 Pins.insert( std::make_pair( pin.ID, pin ) );
1996 }
1997 else if( cNodeName == wxT( "ATTR" ) )
1998 {
1999 ATTRIBUTE_VALUE attr;
2000 attr.Parse( cNode, aContext );
2001 AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
2002 }
2003 else if( cNodeName == wxT( "PINEQUIVALENCE" ) )
2004 {
2005 PIN_EQUIVALENCE pinEq;
2006 pinEq.Parse( cNode, aContext );
2007 PinEquivalences.push_back( pinEq );
2008 }
2009 else if( cNodeName == wxT( "SWAPGROUP" ) )
2010 {
2011 SWAP_GROUP swapGroup;
2012 swapGroup.Parse( cNode, aContext );
2013 SwapGroups.push_back( swapGroup );
2014 }
2015 else
2016 {
2017 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2018 }
2019 }
2020}
2021
2022
2024{
2025 wxASSERT( aNode->GetName() == wxT( "PART" ) );
2026
2027 ID = GetXmlAttributeIDString( aNode, 0 );
2028 Name = GetXmlAttributeIDString( aNode, 1 );
2029
2030 XNODE* cNode = aNode->GetChildren();
2031
2032 for( ; cNode; cNode = cNode->GetNext() )
2033 {
2034 wxString cNodeName = cNode->GetName();
2035
2036 if( cNodeName == wxT( "VERSION" ) )
2037 {
2038 Version = GetXmlAttributeIDLong( cNode, 0 );
2039 }
2040 else if( cNodeName == wxT( "HIDEPINNAMES" ) )
2041 {
2042 HidePinNames = true;
2043 }
2044 else if( cNodeName == wxT( "PARTDEFINITION" ) )
2045 {
2046 Definition.Parse( cNode, aContext );
2047 }
2048 else if( cNodeName == wxT( "PARTPIN" ) )
2049 {
2050 PART_PIN pin;
2051 pin.Parse( cNode, aContext );
2052 PartPins.insert( std::make_pair( pin.ID, pin ) );
2053 }
2054 else if( cNodeName == wxT( "ATTR" ) )
2055 {
2056 ATTRIBUTE_VALUE attr;
2057 attr.Parse( cNode, aContext );
2058 AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
2059 }
2060 else
2061 {
2062 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2063 }
2064 }
2065}
2066
2067
2069{
2070 wxASSERT( aNode->GetName() == wxT( "PARTS" ) );
2071
2072 XNODE* cNode = aNode->GetChildren();
2073
2074 for( ; cNode; cNode = cNode->GetNext() )
2075 {
2076 wxString cNodeName = cNode->GetName();
2077
2078 if( cNodeName == wxT( "PART" ) )
2079 {
2080 PART part;
2081 part.Parse( cNode, aContext );
2082 PartDefinitions.insert( std::make_pair( part.ID, part ) );
2083 }
2084 else
2085 {
2086 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2087 }
2088
2089 aContext->CheckPointCallback();
2090 }
2091}
2092
2093
2095 PARSER_CONTEXT* aContext )
2096{
2097 wxASSERT( aNode->GetName() == wxT( "JPT" ) );
2098
2099 ID = GetXmlAttributeIDString( aNode, 0 );
2100 LayerID = GetXmlAttributeIDString( aNode, 1 );
2101}
2102
2103
2105 PARSER_CONTEXT* aContext )
2106{
2107 wxString cNodeName = aChildNode->GetName();
2108
2109 if( cNodeName == wxT( "PT" ) )
2110 Location.Parse( aChildNode, aContext );
2111 else if( cNodeName == wxT( "FIX" ) )
2112 Fixed = true;
2113 else if( cNodeName == wxT( "GROUPREF" ) )
2114 GroupID = GetXmlAttributeIDString( aChildNode, 0 );
2115 else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
2116 ReuseBlockRef.Parse( aChildNode, aContext );
2117 else
2118 return false;
2119
2120 return true;
2121}
2122
2123
2125{
2126 ParseIdentifiers( aNode, aContext );
2127 XNODE* cNode = aNode->GetChildren();
2128
2129 for( ; cNode; cNode = cNode->GetNext() )
2130 {
2131 if( ParseSubNode( cNode, aContext ) )
2132 continue;
2133 else
2134 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
2135 }
2136}
2137
2138
2140 PARSER_CONTEXT* aContext )
2141{
2142 wxASSERT( aNode->GetName() == wxT( "CONN" ) );
2143
2144 StartNode = GetXmlAttributeIDString( aNode, 0 );
2145 EndNode = GetXmlAttributeIDString( aNode, 1 );
2146 RouteCodeID = GetXmlAttributeIDString( aNode, 2 );
2147}
2148
2149
2151 PARSER_CONTEXT* aContext )
2152{
2153 wxString cNodeName = aChildNode->GetName();
2154
2155 if( cNodeName == wxT( "FIX" ) )
2156 {
2157 Fixed = true;
2158 }
2159 else if( cNodeName == wxT( "HIDDEN" ) )
2160 {
2161 Hidden = true;
2162 }
2163 else if( cNodeName == wxT( "GROUPREF" ) )
2164 {
2165 GroupID = GetXmlAttributeIDString( aChildNode, 0 );
2166 }
2167 else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
2168 {
2169 ReuseBlockRef.Parse( aChildNode, aContext );
2170 }
2171 else if( cNodeName == wxT( "ATTR" ) )
2172 {
2173 ATTRIBUTE_VALUE attrVal;
2174 attrVal.Parse( aChildNode, aContext );
2175 AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) );
2176 }
2177 else
2178 {
2179 return false;
2180 }
2181
2182 return true;
2183}
2184
2185
2187{
2188 wxASSERT( aNode->GetName() == wxT( "NET" ) );
2189
2190 ID = GetXmlAttributeIDString( aNode, 0 );
2191}
2192
2193
2195{
2196 wxString cNodeName = aChildNode->GetName();
2197
2198 if( cNodeName == wxT( "NETCODE" ) )
2199 {
2200 RouteCodeID = GetXmlAttributeIDString( aChildNode, 0 );
2201 }
2202 else if( cNodeName == wxT( "SIGNAME" ) )
2203 {
2204 Name = GetXmlAttributeIDString( aChildNode, 0 );
2205 }
2206 else if( cNodeName == wxT( "SIGNUM" ) )
2207 {
2208 SignalNum = GetXmlAttributeIDLong( aChildNode, 0 );
2209 }
2210 else if( cNodeName == wxT( "HIGHLIT" ) )
2211 {
2212 Highlight = true;
2213 }
2214 else if( cNodeName == wxT( "JPT" ) )
2215 {
2216 JUNCTION jpt;
2217 jpt.Parse( aChildNode, aContext );
2218 Junctions.insert( std::make_pair( jpt.ID, jpt ) );
2219 }
2220 else if( cNodeName == wxT( "NETCLASSREF" ) )
2221 {
2222 NetClassID = GetXmlAttributeIDString( aChildNode, 0 );
2223 }
2224 else if( cNodeName == wxT( "SPACINGCLASS" ) )
2225 {
2226 SpacingClassID = GetXmlAttributeIDString( aChildNode, 0 );
2227 }
2228 else if( cNodeName == wxT( "ATTR" ) )
2229 {
2230 ATTRIBUTE_VALUE attrVal;
2231 attrVal.Parse( aChildNode, aContext );
2232 AttributeValues.insert( std::make_pair( attrVal.AttributeID, attrVal ) );
2233 }
2234 else
2235 {
2236 return false;
2237 }
2238
2239 return true;
2240}
2241
2242
2244{
2245 wxASSERT( aNode->GetName() == wxT( "DOCSYMBOL" ) );
2246
2247 ID = GetXmlAttributeIDString( aNode, 0 );
2248 SymdefID = GetXmlAttributeIDString( aNode, 1 );
2249 LayerID = GetXmlAttributeIDString( aNode, 2 );
2250
2251 XNODE* cNode = aNode->GetChildren();
2252 bool originParsed = false;
2253
2254 for( ; cNode; cNode = cNode->GetNext() )
2255 {
2256 wxString cNodeName = cNode->GetName();
2257
2258 if( !originParsed && cNodeName == wxT( "PT" ) )
2259 {
2260 Origin.Parse( cNode, aContext );
2261 originParsed = true;
2262 }
2263 else if( cNodeName == wxT( "GROUPREF" ) )
2264 {
2265 GroupID = GetXmlAttributeIDString( cNode, 0 );
2266 }
2267 else if( cNodeName == wxT( "REUSEBLOCKREF" ) )
2268 {
2269 ReuseBlockRef.Parse( cNode, aContext );
2270 }
2271 else if( cNodeName == wxT( "FIX" ) )
2272 {
2273 Fixed = true;
2274 }
2275 else if( cNodeName == wxT( "MIRROR" ) )
2276 {
2277 Mirror = true;
2278 }
2279 else if( cNodeName == wxT( "READABILITY" ) )
2280 {
2281 Readability = ParseReadability( cNode );
2282 }
2283 else if( cNodeName == wxT( "ORIENT" ) )
2284 {
2285 OrientAngle = GetXmlAttributeIDLong( cNode, 0 );
2286 }
2287 else if( cNodeName == wxT( "ATTR" ) )
2288 {
2289 ATTRIBUTE_VALUE attr;
2290 attr.Parse( cNode, aContext );
2291 AttributeValues.insert( std::make_pair( attr.AttributeID, attr ) );
2292 }
2293 else if( cNodeName == wxT( "SCALE" ) )
2294 {
2295 ScaleRatioNumerator = GetXmlAttributeIDLong( cNode, 0 );
2296 ScaleRatioDenominator = GetXmlAttributeIDLong( cNode, 1 );
2297 }
2298 else
2299 {
2300 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2301 }
2302 }
2303
2304 if( !originParsed )
2305 THROW_MISSING_PARAMETER_IO_ERROR( wxT( "PT" ), aNode->GetName() );
2306}
2307
2308
2310{
2311 wxASSERT( aNode->GetName() == wxT( "DFLTSETTINGS" ) );
2312
2313 Color = GetXmlAttributeIDString( aNode, 0 );
2314
2315 XNODE* cNode = aNode->GetChildren();
2316
2317 for( ; cNode; cNode = cNode->GetNext() )
2318 {
2319 wxString cNodeName = cNode->GetName();
2320
2321 if( cNodeName == wxT( "INVISIBLE" ) )
2322 {
2323 IsVisible = false;
2324 }
2325 else
2326 {
2327 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2328 }
2329 }
2330}
2331
2332
2334{
2335 wxASSERT( aNode->GetName() == wxT( "ATTRCOL" ) );
2336
2337 AttributeID = GetXmlAttributeIDString( aNode, 0 );
2338 Color = GetXmlAttributeIDString( aNode, 1 );
2339
2340 XNODE* cNode = aNode->GetChildren();
2341
2342 for( ; cNode; cNode = cNode->GetNext() )
2343 {
2344 wxString cNodeName = cNode->GetName();
2345
2346 if( cNodeName == wxT( "INVISIBLE" ) )
2347 {
2348 IsVisible = false;
2349 }
2350 else if( cNodeName == wxT( "NOTPICKABLE" ) )
2351 {
2352 IsPickable = false;
2353 }
2354 else
2355 {
2356 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2357 }
2358 }
2359}
2360
2361
2363{
2364 wxASSERT( aNode->GetName() == wxT( "ATTRCOLORS" ) );
2365
2366 XNODE* cNode = aNode->GetChildren();
2367
2368 for( ; cNode; cNode = cNode->GetNext() )
2369 {
2370 wxString cNodeName = cNode->GetName();
2371
2372 if( cNodeName == wxT( "DFLTSETTINGS" ) )
2373 {
2374 DefaultSettings.Parse( cNode, aContext );
2375 }
2376 else if( cNodeName == wxT( "ATTRCOL" ) )
2377 {
2378 ATTRCOL attrcol;
2379 attrcol.Parse( cNode, aContext );
2380 AttributeColors.insert( { attrcol.AttributeID, attrcol } );
2381 }
2382 else if( cNodeName == wxT( "INVISIBLE" ) )
2383 {
2384 IsVisible = false;
2385 }
2386 else
2387 {
2388 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2389 }
2390 }
2391}
2392
2393
2395{
2396 wxASSERT( aNode->GetName() == wxT( "PARTNAMECOL" ) );
2397
2398 Color = GetXmlAttributeIDString( aNode, 0 );
2399
2400 XNODE* cNode = aNode->GetChildren();
2401
2402 for( ; cNode; cNode = cNode->GetNext() )
2403 {
2404 wxString cNodeName = cNode->GetName();
2405
2406 if( cNodeName == wxT( "INVISIBLE" ) )
2407 {
2408 IsVisible = false;
2409 }
2410 else if( cNodeName == wxT( "NOTPICKABLE" ) )
2411 {
2412 IsPickable = false;
2413 }
2414 else
2415 {
2416 THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
2417 }
2418 }
2419}
2420
2421
2423{
2424 static const wxString c_numAttributes = wxT( "numAttributes" );
2425
2426 wxString result;
2427 long numAttributes = 0;
2428
2429 if( aNode->GetAttribute( c_numAttributes, &result ) )
2430 {
2431 numAttributes = wxAtol( result );
2432 aNode->DeleteAttribute( c_numAttributes );
2433 ++numAttributes;
2434 }
2435
2436#if wxUSE_UNICODE_WCHAR
2437 std::wstring numAttrStr = std::to_wstring( numAttributes );
2438#else
2439 std::string numAttrStr = std::to_string( numAttributes );
2440#endif
2441
2442 aNode->AddAttribute( c_numAttributes, numAttrStr );
2443
2444 wxString paramName = wxT( "attr" );
2445 paramName << numAttrStr;
2446
2447 aNode->AddAttribute( paramName, aValue );
2448}
2449
2450
2452 const wxString& aFileTypeIdentifier, PROGRESS_REPORTER* aProgressReporter )
2453{
2454 KEYWORD emptyKeywords[1] = {};
2455 XNODE* rootNode = nullptr;
2456 XNODE* cNode = nullptr;
2457 XNODE* iNode = nullptr;
2458 int tok;
2459 bool cadstarFileCheckDone = false;
2460 wxString str;
2461 wxCSConv win1252( wxT( "windows-1252" ) );
2462 wxMBConv* conv = &win1252; // Initial testing suggests file encoding to be Windows-1252
2463 // More samples required.
2464
2465 // Open the file and get the file size
2466 FILE* fp = wxFopen( aFileName, wxT( "rt" ) );
2467
2468 if( !fp )
2469 THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'" ), aFileName ) );
2470
2471 fseek( fp, 0L, SEEK_END );
2472 long fileSize = ftell( fp );
2473 rewind( fp );
2474
2475 DSNLEXER lexer( emptyKeywords, 0, nullptr, fp, aFileName );
2476
2477 auto currentProgress = [&]() -> double
2478 {
2479 return static_cast<double>( ftell( fp ) ) / fileSize;
2480 };
2481
2482 double previousReportedProgress = -1.0;
2483
2484 while( ( tok = lexer.NextTok() ) != DSN_EOF )
2485 {
2486 if( aProgressReporter && ( currentProgress() - previousReportedProgress ) > 0.01 )
2487 {
2488 if( !aProgressReporter->KeepRefreshing() )
2489 {
2490 delete rootNode;
2491 THROW_IO_ERROR( _( "File import cancelled by user." ) );
2492 }
2493
2494 aProgressReporter->SetCurrentProgress( currentProgress() );
2495 previousReportedProgress = currentProgress();
2496 }
2497
2498 if( tok == DSN_RIGHT )
2499 {
2500 cNode = iNode;
2501 if( cNode )
2502 {
2503 iNode = cNode->GetParent();
2504 }
2505 else
2506 {
2507 //too many closing brackets
2508 delete rootNode;
2509 THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
2510 }
2511 }
2512 else if( tok == DSN_LEFT )
2513 {
2514 tok = lexer.NextTok();
2515 str = wxString( lexer.CurText(), *conv );
2516 cNode = new XNODE( wxXML_ELEMENT_NODE, str );
2517
2518 if( !rootNode )
2519 rootNode = cNode;
2520
2521 if( iNode )
2522 {
2523 //we will add it as attribute as well as child node
2524 InsertAttributeAtEnd( iNode, str );
2525 iNode->AddChild( cNode );
2526 }
2527 else if( !cadstarFileCheckDone )
2528 {
2529 if( cNode->GetName() != aFileTypeIdentifier )
2530 {
2531 delete rootNode;
2532 THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
2533 }
2534
2535 cadstarFileCheckDone = true;
2536 }
2537
2538 iNode = cNode;
2539 }
2540 else if( iNode )
2541 {
2542 str = wxString( lexer.CurText(), *conv );
2543 //Insert even if string is empty
2544 InsertAttributeAtEnd( iNode, str );
2545 }
2546 else
2547 {
2548 //not enough closing brackets
2549 delete rootNode;
2550 THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
2551 }
2552 }
2553
2554 // Not enough closing brackets
2555 if( iNode != nullptr )
2556 {
2557 delete rootNode;
2558 THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
2559 }
2560
2561 // Throw if no data was parsed
2562 if( rootNode )
2563 {
2564 return rootNode;
2565 }
2566 else
2567 {
2568 delete rootNode;
2569 THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
2570 }
2571
2572 return nullptr;
2573}
2574
2575
2576bool CADSTAR_ARCHIVE_PARSER::IsValidAttribute( wxXmlAttribute* aAttribute )
2577{
2578 return aAttribute->GetName() != wxT( "numAttributes" );
2579}
2580
2581
2583 bool aIsRequired )
2584{
2585#if wxUSE_UNICODE_WCHAR
2586 std::wstring idStr = std::to_wstring( aID );
2587#else
2588 std::string idStr = std::to_string( aID );
2589#endif
2590
2591 wxString attrName = wxS( "attr" );
2592 attrName << idStr;
2593
2594 wxString retVal;
2595
2596 if( !aNode->GetAttribute( attrName, &retVal ) )
2597 {
2598 if( aIsRequired )
2599 THROW_MISSING_PARAMETER_IO_ERROR( std::to_string( aID ), aNode->GetName() );
2600 else
2601 return wxEmptyString;
2602 }
2603
2604 return retVal;
2605}
2606
2607
2609 bool aIsRequired )
2610{
2611 long retVal;
2612 bool success = GetXmlAttributeIDString( aNode, aID, aIsRequired ).ToLong( &retVal );
2613
2614 if( !success )
2615 {
2616 if( aIsRequired )
2617 THROW_PARSING_IO_ERROR( std::to_string( aID ), aNode->GetName() );
2618 else
2619 return UNDEFINED_VALUE;
2620 }
2621
2622 return retVal;
2623}
2624
2625
2627{
2628 if( aNode && aNode->GetChildren() )
2629 THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() );
2630}
2631
2632
2634{
2635 if( aNode && aNode->GetNext() )
2636 THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetNext()->GetName(), aNode->GetParent()->GetName() );
2637}
2638
2639
2641 EVALUE& aValueToParse )
2642{
2643 if( aNode->GetChildren()->GetName() == wxT( "E" ) )
2644 aValueToParse.Parse( aNode->GetChildren(), aContext );
2645 else
2646 THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aNode->GetName() );
2647}
2648
2649
2650std::vector<CADSTAR_ARCHIVE_PARSER::POINT> CADSTAR_ARCHIVE_PARSER::ParseAllChildPoints(
2651 XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes, int aExpectedNumPoints )
2652{
2653 std::vector<POINT> retVal;
2654
2655 XNODE* cNode = aNode->GetChildren();
2656
2657 for( ; cNode; cNode = cNode->GetNext() )
2658 {
2659 if( cNode->GetName() == wxT( "PT" ) )
2660 {
2661 POINT pt;
2662 //TODO try.. catch + throw again with more detailed error information
2663 pt.Parse( cNode, aContext );
2664 retVal.push_back( pt );
2665 }
2666 else if( aTestAllChildNodes )
2667 {
2668 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
2669 }
2670 }
2671
2672 if( aExpectedNumPoints != UNDEFINED_VALUE
2673 && retVal.size() != static_cast<size_t>( aExpectedNumPoints ) )
2674 {
2675 THROW_IO_ERROR( wxString::Format(
2676 _( "Unexpected number of points in '%s'. Found %d but expected %d." ),
2677 aNode->GetName(), retVal.size(), aExpectedNumPoints ) );
2678 }
2679
2680 return retVal;
2681}
2682
2683
2684std::vector<CADSTAR_ARCHIVE_PARSER::VERTEX> CADSTAR_ARCHIVE_PARSER::ParseAllChildVertices(
2685 XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes )
2686{
2687 std::vector<VERTEX> retVal;
2688
2689 XNODE* cNode = aNode->GetChildren();
2690
2691 for( ; cNode; cNode = cNode->GetNext() )
2692 {
2693 if( VERTEX::IsVertex( cNode ) )
2694 {
2695 VERTEX vertex;
2696 //TODO try.. catch + throw again with more detailed error information
2697 vertex.Parse( cNode, aContext );
2698 retVal.push_back( vertex );
2699 }
2700 else if( aTestAllChildNodes )
2701 {
2702 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
2703 }
2704 }
2705
2706 return retVal;
2707}
2708
2709
2710std::vector<CADSTAR_ARCHIVE_PARSER::CUTOUT> CADSTAR_ARCHIVE_PARSER::ParseAllChildCutouts(
2711 XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes )
2712{
2713 std::vector<CUTOUT> retVal;
2714
2715 XNODE* cNode = aNode->GetChildren();
2716
2717 for( ; cNode; cNode = cNode->GetNext() )
2718 {
2719 if( cNode->GetName() == wxT( "CUTOUT" ) )
2720 {
2721 CUTOUT cutout;
2722 //TODO try.. catch + throw again with more detailed error information
2723 cutout.Parse( cNode, aContext );
2724 retVal.push_back( cutout );
2725 }
2726 else if( aTestAllChildNodes )
2727 {
2728 THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), aNode->GetName() );
2729 }
2730 }
2731
2732 return retVal;
2733}
2734
2735
2737{
2738 XNODE* childNodes = aNode->GetChildren();
2739 long retval = 0;
2740
2741 for( ; childNodes; childNodes = childNodes->GetNext() )
2742 retval++;
2743
2744 return retval;
2745}
2746
2747
2748long CADSTAR_ARCHIVE_PARSER::GetNumberOfStepsForReporting( XNODE* aRootNode, std::vector<wxString> aSubNodeChildrenToCount )
2749{
2750 XNODE* level1Node = aRootNode->GetChildren();
2751 long retval = 0;
2752
2753 for( ; level1Node; level1Node = level1Node->GetNext() )
2754 {
2755 for( wxString childNodeName : aSubNodeChildrenToCount )
2756 {
2757 if( level1Node->GetName() == childNodeName )
2758 retval += GetNumberOfChildNodes( level1Node );
2759 }
2760
2761 retval++;
2762 }
2763
2764 return retval;
2765}
2766
2767
2768wxString CADSTAR_ARCHIVE_PARSER::HandleTextOverbar( wxString aCadstarString )
2769{
2770 wxString escapedText = aCadstarString;
2771
2772 escapedText.Replace( wxT( "'" ), wxT( "~" ) );
2773
2774 return ConvertToNewOverbarNotation( escapedText );
2775}
2776
2777
2779{
2780 if( !aKiCadTextItem->GetText().IsEmpty() )
2781 {
2782 VECTOR2I positionOffset( 0, aKiCadTextItem->GetInterline() );
2783 RotatePoint( positionOffset, aKiCadTextItem->GetTextAngle() );
2784
2785 if( aInvertY )
2786 positionOffset.y = -positionOffset.y;
2787
2788 //Count num of additional lines
2789 wxString text = aKiCadTextItem->GetText();
2790 int numExtraLines = text.Replace( "\n", "\n" );
2791 numExtraLines -= text.at( text.size() - 1 ) == '\n'; // Ignore new line character at end
2792 positionOffset.x *= numExtraLines;
2793 positionOffset.y *= numExtraLines;
2794
2795 aKiCadTextItem->Offset( positionOffset );
2796 }
2797}
2798
2799
2800wxString CADSTAR_ARCHIVE_PARSER::generateLibName( const wxString& aRefName,
2801 const wxString& aAlternateName )
2802{
2803 if( aAlternateName.IsEmpty() )
2804 return EscapeString( aRefName, CTX_LIBID );
2805 else
2806 return EscapeString( aRefName + wxT( " (" ) + aAlternateName + wxT( ")" ), CTX_LIBID );
2807}
2808
2809
2811{
2812 if( m_progressReporter )
2813 {
2815
2817 THROW_IO_ERROR( _( "File import cancelled by user." ) );
2818 }
2819}
2820
KICAD_PLUGIN_EXPORT SCENEGRAPH * Load(char const *aFileName)
reads a model file and creates a generic display structure
CADSTAR_PIN_POSITION
Positioning of pin names can be in one of four quadrants.
CADSTAR_PIN_TYPE
file: cadstar_archive_objects.h Contains common object definitions
Helper functions and common defines between schematic and PCB Archive files.
#define SYMBOL_NAME_ATTRID
Symbol Name attribute ID - used for placement of designators on the schematic.
#define SIGNALNAME_ORIGIN_ATTRID
#define THROW_MISSING_NODE_IO_ERROR(nodename, location)
#define THROW_UNKNOWN_NODE_IO_ERROR(nodename, location)
#define LINK_ORIGIN_ATTRID
#define COMPONENT_NAME_2_ATTRID
Component Name 2 Attribute ID - typically used for indicating the placement of designators in placeme...
#define THROW_UNKNOWN_PARAMETER_IO_ERROR(param, location)
#define COMPONENT_NAME_ATTRID
Component Name Attribute ID - typically used for placement of designators on silk screen.
#define PART_NAME_ATTRID
#define THROW_MISSING_PARAMETER_IO_ERROR(param, location)
#define THROW_PARSING_IO_ERROR(param, location)
READABILITY
Sets the readability direction of text.
@ BOTTOM_TO_TOP
When text is vertical, show it rotated 90 degrees anticlockwise.
@ TOP_TO_BOTTOM
When text is vertical, show it rotated 90 degrees clockwise.
@ STEPGRID
Param1 = X Step, Param2 = Y Step. A standard x,y grid.
@ FRACTIONALGRID
Param1 = Units, Param2 = Divisor.
SWAP_RULE
Corresponds to "Display when" Item property.
@ USE_SWAP_LAYER
Display when Mirrored.
@ NO_SWAP
Display when Unmirrored.
static UNITS ParseUnits(XNODE *aNode)
static ALIGNMENT ParseAlignment(XNODE *aNode)
static const std::map< TEXT_FIELD_NAME, wxString > CADSTAR_TO_KICAD_FIELDS
Map between CADSTAR fields and KiCad text variables.
TEXT_FIELD_NAME
These are special fields in text objects enclosed between the tokens '<@' and '>' such as <@[FIELD_NA...
static SWAP_RULE ParseSwapRule(XNODE *aNode)
ALIGNMENT
From CADSTAR Help: "Text Alignment enables you to define the position of an alignment origin for all ...
@ NO_ALIGNMENT
NO_ALIGNMENT has different meaning depending on the object type.
static const long UNDEFINED_VALUE
static void FixTextPositionNoAlignment(EDA_TEXT *aKiCadTextItem, bool aInvertY=false)
Corrects the position of a text element that had NO_ALIGNMENT in CADSTAR.
static wxString generateLibName(const wxString &aRefName, const wxString &aAlternateName)
static void CheckNoNextNodes(XNODE *aNode)
static std::vector< CUTOUT > ParseAllChildCutouts(XNODE *aNode, PARSER_CONTEXT *aContext, bool aTestAllChildNodes=false)
if no children are present, it just returns an empty vector (without throwing an exception)
static XNODE * LoadArchiveFile(const wxString &aFileName, const wxString &aFileTypeIdentifier, PROGRESS_REPORTER *aProgressReporter=nullptr)
Reads a CADSTAR Archive file (S-parameter format)
static JUSTIFICATION ParseJustification(XNODE *aNode)
static wxString ParseTextFields(const wxString &aTextString, PARSER_CONTEXT *aParserContext)
Replaces CADSTAR fields for the equivalent in KiCad and stores the field values in aParserContext.
@ PART_DEFINITION
From CADSTAR Help: Assigned to Parts library Definitions and displayed by the Library searcher.
@ BOTH
From CADSTAR Help: Assigned to both Schematic symbols and PCB components, and displayed on Schematic ...
@ COMPONENT
From CADSTAR Help: Assigned to PCB components and displayed on PCB designs.
@ SYMBOL
From CADSTAR Help: Assigned to Schematic Symbols and displayed on Schematic Designs.
@ PART_LIBRARY
From CADSTAR Help: Only used by non-Cadstar applications.
static std::vector< VERTEX > ParseAllChildVertices(XNODE *aNode, PARSER_CONTEXT *aContext, bool aTestAllChildNodes=false)
if no children are present, it just returns an empty vector (without throwing an exception)
static ANGUNITS ParseAngunits(XNODE *aNode)
long PART_DEFINITION_PIN_ID
Pin identifier in the part definition.
@ OUTLINE
Unfilled closed shape.
@ OPENSHAPE
Unfilled open shape. Cannot have cutouts.
@ SOLID
Filled closed shape (solid fill).
@ HATCHED
Filled closed shape (hatch fill).
static const double TXT_HEIGHT_RATIO
CADSTAR fonts are drawn on a 24x24 integer matrix, where the each axis goes from 0 to 24.
static wxString GetXmlAttributeIDString(XNODE *aNode, unsigned int aID, bool aIsRequired=true)
void checkPoint()
Updates m_progressReporter or throws if user cancelled.
static bool IsValidAttribute(wxXmlAttribute *aAttribute)
static READABILITY ParseReadability(XNODE *aNode)
static std::vector< POINT > ParseAllChildPoints(XNODE *aNode, PARSER_CONTEXT *aContext, bool aTestAllChildNodes=false, int aExpectedNumPoints=UNDEFINED_VALUE)
if no children are present, it just returns an empty vector (without throwing an exception)
@ DESIGN
Inherits from design units (assumed Assignments->Technology->Units)
static wxString HandleTextOverbar(wxString aCadstarString)
Convert a string with CADSTAR overbar characters to equivalent in KiCad.
static void CheckNoChildNodes(XNODE *aNode)
static long GetXmlAttributeIDLong(XNODE *aNode, unsigned int aID, bool aIsRequired=true)
JUSTIFICATION
From CADSTAR Help: "Multi Line Text can also be justified as Left, Centre or Right.
static void ParseChildEValue(XNODE *aNode, PARSER_CONTEXT *aContext, EVALUE &aValueToParse)
static long GetNumberOfStepsForReporting(XNODE *aRootNode, std::vector< wxString > aSubNodeChildrenToCount)
PROGRESS_REPORTER * m_progressReporter
static long GetNumberOfChildNodes(XNODE *aNode)
static void InsertAttributeAtEnd(XNODE *aNode, wxString aValue)
@ PART_DEFINITION
Only library Attributes.
@ PART
Only library Attributes.
Implement a lexical analyzer for the SPECCTRA DSN file format.
Definition: dsnlexer.h:80
const char * CurText() const
Return a pointer to the current token's text.
Definition: dsnlexer.h:399
int NextTok()
Return the next token found in the input file or DSN_EOF when reaching the end of file.
Definition: dsnlexer.cpp:518
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:134
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
int GetInterline() const
Return the distance between two lines of text.
Definition: eda_text.cpp:561
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:437
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Definition: shape_arc.cpp:212
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
Hold an XML or S-expression element.
Definition: xnode.h:44
XNODE * GetParent() const
Definition: xnode.h:72
XNODE * GetChildren() const
Definition: xnode.h:62
XNODE * GetNext() const
Definition: xnode.h:67
@ DSN_LEFT
Definition: dsnlexer.h:68
@ DSN_RIGHT
Definition: dsnlexer.h:67
@ DSN_EOF
Definition: dsnlexer.h:70
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
Definition: string_utils.h:54
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void ParseIdentifiers(XNODE *aNode, PARSER_CONTEXT *aContext)
virtual void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
NOTE from CADSTAR help: To convert a Part Definition Attribute into a hyperlink, prefix the attribute...
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
Represents a cutout in a closed shape (e.g.
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
Represents a floating value in E notation.
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
long Version
Archive version number (e.g.
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
long SomeInt
It is unclear what this parameter is used for.
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
static bool IsGrid(XNODE *aNode)
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void ParseIdentifiers(XNODE *aNode, PARSER_CONTEXT *aContext)
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
virtual void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void ParseIdentifiers(XNODE *aNode, PARSER_CONTEXT *aContext)
NETELEMENT_ID ID
First character is "J".
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
void ParseIdentifiers(XNODE *aNode, PARSER_CONTEXT *aContext)
std::map< TEXT_FIELD_NAME, wxString > TextFieldToValuesMap
Values for the text field elements used in the CADSTAR design extracted from the text element instanc...
std::map< wxString, wxString > FilenamesToTextMap
CADSTAR doesn't have user defined text fields but does allow loading text from a file.
std::map< wxString, wxString > TextToHyperlinksMap
KiCad doesn't support hyperlinks but we use this map to display warning messages after import.
std::set< TEXT_FIELD_NAME > InconsistentTextFields
Text fields need to be updated in CADSTAR and it is possible that they are not consistent across text...
std::function< void()> CheckPointCallback
Callback function to report progress.
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
< "SWAPGATE" Node name (represents an "Element")
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
static CADSTAR_PIN_TYPE GetPinType(XNODE *aNode)
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
Represents a point in x,y coordinates.
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
bool IsEmpty()
Determines if this is empty (i.e. no design reuse associated)
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
virtual void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
SHAPE_POLY_SET ConvertToPolySet(const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, double aAccuracy) const
SHAPE_LINE_CHAIN OutlineAsChain(const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, double aAccuracy) const
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
bool ParseSubNode(XNODE *aChildNode, PARSER_CONTEXT *aContext)
void ParseIdentifiers(XNODE *aNode, PARSER_CONTEXT *aContext)
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
Corresponds to CADSTAR "origin".
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
< Nodename = "VARIANT" or "VMASTER" (master variant
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
Represents a vertex in a shape.
SHAPE_ARC BuildArc(const VECTOR2I &aPrevPoint, const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback) const
void AppendToChain(SHAPE_LINE_CHAIN *aChainToAppendTo, const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, double aAccuracy) const
void Parse(XNODE *aNode, PARSER_CONTEXT *aContext) override
Hold a keyword string and its unique integer token.
Definition: dsnlexer.h:41
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588