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