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.h
23  * @brief Helper functions and common defines between schematic and PCB Archive files
24  */
25 
26 #ifndef CADSTAR_ARCHIVE_PARSER_H_
27 #define CADSTAR_ARCHIVE_PARSER_H_
28 
29 #include <richio.h>
30 #include <wx/gdicmn.h>
31 #include <functional>
32 #include <map>
33 #include <set>
34 #include <vector>
35 #include <xnode.h>
36 
37 // THROW_IO_ERROR definitions to ensure consistent wording is used in the error messages
38 
39 #define THROW_MISSING_NODE_IO_ERROR( nodename, location ) \
40     THROW_IO_ERROR( wxString::Format( _( "Missing node '%s' in '%s'" ), nodename, location ) )
41 
42 #define THROW_UNKNOWN_NODE_IO_ERROR( nodename, location ) \
43     THROW_IO_ERROR( wxString::Format( _( "Unknown node '%s' in '%s'" ), nodename, location ) )
44 
45 #define THROW_MISSING_PARAMETER_IO_ERROR( param, location ) \
46     THROW_IO_ERROR( wxString::Format( _( "Missing Parameter '%s' in '%s'" ), param, location ) )
47 
48 #define THROW_UNKNOWN_PARAMETER_IO_ERROR( param, location ) \
49     THROW_IO_ERROR( wxString::Format( _( "Unknown Parameter '%s' in '%s'" ), param, location ) )
50 
51 #define THROW_PARSING_IO_ERROR( param, location ) \
52     THROW_IO_ERROR( wxString::Format( _( "Unable to parse '%s' in '%s'" ), param, location ) )
53 
54 //=================================
55 // MACRO DEFINITIONS
56 //=================================
57 #define UNDEFINED_LAYER_ID ( LAYER_ID ) wxEmptyString
58 
59 
60 /**
61  * Component Name Attribute ID - typically used for placement of designators on silk screen.
62  */
63 #define COMPONENT_NAME_ATTRID ( ATTRIBUTE_ID ) wxT( "__COMPONENT_NAME__" )
64 
65 /**
66  * Component Name 2 Attribute ID - typically used for indicating the placement of designators in
67  * placement drawings.
68  */
69 #define COMPONENT_NAME_2_ATTRID ( ATTRIBUTE_ID ) wxT( "__COMPONENT_NAME_2__" )
70 
71 /**
72  * Symbol Name attribute ID - used for placement of designators on the schematic
73  */
74 #define SYMBOL_NAME_ATTRID ( ATTRIBUTE_ID ) wxT( "__SYMBOL_NAME__" )
75 #define LINK_ORIGIN_ATTRID ( ATTRIBUTE_ID ) wxT( "__LINK_ORIGIN__" )
76 #define SIGNALNAME_ORIGIN_ATTRID ( ATTRIBUTE_ID ) wxT( "__SIGNALNAME_ORIGIN__" )
77 #define PART_NAME_ATTRID ( ATTRIBUTE_ID ) wxT( "__PART_NAME__" )
78 
79 class EDA_TEXT;
80 class wxXmlAttribute;
81 class PROGRESS_REPORTER;
82 
83 /**
84  * @brief Helper functions and common structures for CADSTAR PCB and Schematic archive files.
85  */
86 class CADSTAR_ARCHIVE_PARSER
87 {
88 public:
CADSTAR_ARCHIVE_PARSER()89     CADSTAR_ARCHIVE_PARSER() { m_progressReporter = nullptr; }
90 
91 
92     typedef wxString LINECODE_ID;
93     typedef wxString HATCHCODE_ID;
94     typedef wxString ROUTECODE_ID;
95     typedef wxString NETCLASS_ID;
96     typedef wxString SPACING_CLASS_ID;
97     typedef wxString TEXTCODE_ID;
98     typedef wxString LAYER_ID; ///< ID of a Sheet (if schematic) or board Layer (if PCB)
99     typedef wxString VARIANT_ID;
100     typedef wxString ATTRIBUTE_ID;
101     typedef wxString SYMDEF_ID;
102     typedef wxString PART_ID;
103     typedef wxString GATE_ID;
104     typedef long     TERMINAL_ID;            ///< Terminal is the pin identifier in the schematic
105     typedef long     PART_DEFINITION_PIN_ID; ///< Pin identifier in the part definition
106     typedef long     PART_PIN_ID;            ///< Pin identifier in the part
107     typedef wxString TEXT_ID;
108     typedef wxString FIGURE_ID;
109     typedef wxString GROUP_ID;
110     typedef wxString REUSEBLOCK_ID;
111     typedef wxString NET_ID;
112     typedef wxString NETELEMENT_ID;
113     typedef wxString DOCUMENTATION_SYMBOL_ID;
114     typedef wxString COLOR_ID;
115 
116     static const long UNDEFINED_VALUE = -1;
117 
118     /**
119      * CADSTAR fonts are drawn on a 24x24 integer matrix, where the each axis goes from 0 to 24.
120      * The characters can each specify a width of between 12 and 24, but the height is fixed at 24.
121      *
122      * The default CADSTAR font uses y=5 as the starting point for capital letters, leaving space
123      * for the tails of letters such as "g", "p", "y", "q", etc.
124      *
125      * The font height in CADSTAR corresponds to the full 24 point height. In KiCad it only
126      * corresponds to the height above the guide line, meaning the overall text height will be
127      * larger in KiCad.
128      */
129     static const double TXT_HEIGHT_RATIO;
130 
131     /**
132      * These are special fields in text objects enclosed between the tokens '<@' and '@>' such as
133      * <@[FIELD_NAME][FIELD_VALUE]@>. For example: "<@DESIGN TITLEProject Title@>"
134      */
135     enum class TEXT_FIELD_NAME
136     {
137         DESIGN_TITLE,
138         SHORT_JOBNAME,
139         LONG_JOBNAME,
140         NUM_OF_SHEETS,
141         SHEET_NUMBER,
142         SHEET_NAME,
143         VARIANT_NAME,
144         VARIANT_DESCRIPTION,
145         REG_USER,
146         COMPANY_NAME,
147         CURRENT_USER,
148         DATE,
149         TIME,
150         MACHINE_NAME,
151         FROM_FILE,
152         DISTANCE,
153         UNITS_SHORT,
154         UNITS_ABBREV,
155         UNITS_FULL,
156         HYPERLINK,
157         NONE ///< Synthetic for flagging
158     };
159 
160     /**
161      * Map between CADSTAR fields and KiCad text variables. This is used as a lookup table when
162      * parsing CADSTAR text fields. Most variables have a similar name in KiCad as in CADSTAR.
163      */
164     static const std::map<TEXT_FIELD_NAME, wxString> CADSTAR_TO_KICAD_FIELDS;
165 
166 
167     struct PARSER_CONTEXT
168     {
169         /**
170          * CADSTAR doesn't have user defined text fields but does allow loading text from a
171          * file. This map stores all the text items that exist in the original CADSTAR design. They
172          * will be replaced by a text variable of the form ${FROM_FILE_[filename]_[extension]}
173          */
174         std::map<wxString, wxString> FilenamesToTextMap;
175 
176         /**
177          * KiCad doesn't support hyperlinks but we use this map to display warning messages
178          * after import. First element = Display Text. Second element = Hyperlink
179          */
180         std::map<wxString, wxString> TextToHyperlinksMap;
181 
182         /**
183          * Values for the text field elements used in the CADSTAR design extracted from the
184          * text element instances
185          */
186         std::map<TEXT_FIELD_NAME, wxString> TextFieldToValuesMap;
187 
188         /**
189          * Text fields need to be updated in CADSTAR and it is possible that they are not
190          * consistent across text elements.
191          */
192         std::set<TEXT_FIELD_NAME> InconsistentTextFields;
193 
194         /**
195          * Callback function to report progress
196          */
197         std::function<void()> CheckPointCallback = []() {};
198     };
199 
200     /**
201      * @brief Replaces CADSTAR fields for the equivalent in KiCad and stores the field values
202      * in aParserContext
203      * @param aTextString Text string to parse
204      * @param aParserContext PARSER_CONTEXT in which to store the values of the found fields
205      * @return
206      */
207     static wxString ParseTextFields( const wxString& aTextString, PARSER_CONTEXT* aParserContext );
208 
209 
210     struct PARSER
211     {
212         virtual void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) = 0;
213 
~PARSERPARSER214         virtual ~PARSER() {};
215     };
216 
217 
218     struct FORMAT : PARSER
219     {
220         wxString Type;
221         long     SomeInt; ///< It is unclear what this parameter is used for
222         long     Version; ///< Archive version number (e.g. for PCB: 19=> CADSTAR 17.0 archive,
223                           ///<  20=> CADSTAR 18.0 archive, 21 => CADSTAR 2018.0 / 2019.0 / 2020.0,
224                           ///<  etc.)
225         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
226     };
227 
228 
229     struct TIMESTAMP : PARSER
230     {
231         long Year;
232         long Month;
233         long Day;
234         long Hour;
235         long Minute;
236         long Second;
237 
238         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
239     };
240 
241     //Note: there are possibly several other resolutions, but HUNDREDTH MICRON is only one known
242     enum class RESOLUTION
243     {
244         HUNDREDTH_MICRON
245     };
246 
247 
248     struct HEADER : PARSER
249     {
250         FORMAT     Format;
251         wxString   JobFile;
252         wxString   JobTitle;
253         wxString   Generator;
254         RESOLUTION Resolution;
255         TIMESTAMP  Timestamp;
256 
257         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
258     };
259 
260 
261     struct VARIANT : PARSER ///< Nodename = "VARIANT" or "VMASTER" (master variant
262     {
263         VARIANT_ID ID          = wxEmptyString;
264         VARIANT_ID ParentID    = wxEmptyString; ///< if empty, then this one is the master
265         wxString   Name        = wxEmptyString;
266         wxString   Description = wxEmptyString;
267 
268         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
269     };
270 
271 
272     struct VARIANT_HIERARCHY : PARSER
273     {
274         std::map<VARIANT_ID, VARIANT> Variants;
275 
276         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
277     };
278 
279 
280     enum class LINESTYLE
281     {
282         SOLID,
283         DASH,
284         DASHDOT,
285         DASHDOTDOT,
286         DOT
287     };
288 
289 
290     struct LINECODE : PARSER
291     {
292         LINECODE_ID ID;
293         wxString    Name;
294         long        Width;
295         LINESTYLE   Style;
296 
297         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
298     };
299 
300 
301     struct HATCH : PARSER
302     {
303         long Step;
304         long LineWidth;
305         long OrientAngle; ///< 1/1000 of a Degree
306 
307         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
308     };
309 
310 
311     struct HATCHCODE : PARSER
312     {
313         HATCHCODE_ID       ID;
314         wxString           Name;
315         std::vector<HATCH> Hatches;
316 
317         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
318     };
319 
320 
321     static const long FONT_NORMAL = 400;
322     static const long FONT_BOLD   = 700;
323 
324 
325     struct FONT : PARSER
326     {
327         wxString Name  = wxT( "CADSTAR" );
328         long Modifier1 = FONT_NORMAL; ///< It seems this is related to weight. 400=Normal, 700=Bold.
329         long Modifier2 = 0;           ///< It seems this is always 0 regardless of settings
330         bool KerningPairs =
331                 false; ///< From CADSTAR Help: "Kerning Pairs is for causing the system to
332                        ///< automatically reduce the spacing between certain pairs of
333                        ///< characters in order to improve the appearance of the text"
334         bool Italic = false;
335 
336         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
337     };
338 
339 
340     struct TEXTCODE : PARSER
341     {
342         TEXTCODE_ID ID;
343         wxString    Name;
344         long        LineWidth;
345         long        Height;
346         long Width; ///< Defaults to 0 if using system fonts or, if using CADSTAR font, default to
347                     ///< equal height (1:1 aspect ratio). Allows for system fonts to be rendered in
348                     ///< a different aspect ratio.
349         FONT Font;
350 
351         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
352     };
353 
354 
355     struct ROUTEREASSIGN : PARSER
356     {
357         LAYER_ID LayerID;
358         long     OptimalWidth;
359         long     MinWidth;
360         long     MaxWidth;
361         long     NeckedWidth;
362 
363         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
364     };
365 
366 
367     struct ROUTECODE : PARSER
368     {
369         ROUTECODE_ID ID;
370         wxString     Name;
371         long         OptimalWidth;
372         long         MinWidth;
373         long         MaxWidth;
374         long         NeckedWidth;
375 
376         std::vector<ROUTEREASSIGN> RouteReassigns;
377 
378         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
379     };
380 
381 
382     /**
383      * @brief Represents a floating value in E notation
384      */
385     struct EVALUE : PARSER
386     {
387         long Base     = 0;
388         long Exponent = 0;
389 
390         void   Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
391         double GetDouble();
392     };
393 
394     /**
395      * @brief Represents a point in x,y coordinates
396      */
397     struct POINT : wxPoint, PARSER
398     {
POINTPOINT399         POINT() : wxPoint( UNDEFINED_VALUE, UNDEFINED_VALUE )
400         {
401         }
402 
403         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
404     };
405 
406 
407     struct LONGPOINT : PARSER
408     {
409         long x = UNDEFINED_VALUE;
410         long y = UNDEFINED_VALUE;
411 
412         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
413     };
414 
415 
416     enum class VERTEX_TYPE
417     {
418         POINT,
419         CLOCKWISE_ARC,
420         CLOCKWISE_SEMICIRCLE,
421         ANTICLOCKWISE_ARC,
422         ANTICLOCKWISE_SEMICIRCLE
423     };
424 
425     /**
426      * @brief Represents a vertex in a shape. E.g. A circle is made by two semicircles with the same
427      * center point.
428      */
429     struct VERTEX : PARSER
430     {
431         VERTEX_TYPE Type;
432         POINT       Center;
433         POINT       End;
434 
435         static bool IsVertex( XNODE* aNode );
436         void        Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
437     };
438 
439     /**
440      * @brief Represents a cutout in a closed shape (e.g. OUTLINE)
441      */
442     struct CUTOUT : PARSER
443     {
444         std::vector<VERTEX> Vertices;
445 
446         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
447     };
448 
449 
450     enum class SHAPE_TYPE
451     {
452         OPENSHAPE, ///< Unfilled open shape. Cannot have cutouts.
453         OUTLINE,   ///< Unfilled closed shape.
454         SOLID,     ///< Filled closed shape (solid fill).
455         HATCHED    ///< Filled closed shape (hatch fill).
456     };
457 
458 
459     struct SHAPE : PARSER
460     {
461         SHAPE_TYPE          Type;
462         std::vector<VERTEX> Vertices;
463         std::vector<CUTOUT> Cutouts;     ///< Not Applicable to OPENSHAPE Type
464         wxString            HatchCodeID; ///< Only Applicable for HATCHED Type
465 
466         static bool IsShape( XNODE* aNode );
467         void        Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
468     };
469 
470 
471     enum class UNITS
472     {
473         DESIGN, ///< Inherits from design units (assumed Assignments->Technology->Units)
474         THOU,
475         INCH,
476         MICROMETRE,
477         MM,
478         CENTIMETER,
479         METER
480     };
481 
482 
483     static UNITS ParseUnits( XNODE* aNode );
484 
485 
486     enum class ANGUNITS
487     {
488         DEGREES,
489         RADIANS
490     };
491 
492 
493     static ANGUNITS ParseAngunits( XNODE* aNode );
494 
495 
496     enum class GRID_TYPE
497     {
498         FRACTIONALGRID, ///< Param1 = Units, Param2 = Divisor. The grid is equal in X and Y
499                         ///< dimensions with a step size equal to Param1/Param2
500         STEPGRID        ///< Param1 = X Step, Param2 = Y Step. A standard x,y grid.
501     };
502 
503 
504     struct GRID : PARSER
505     {
506         GRID_TYPE Type;
507         wxString  Name;
508         long      Param1; ///< Either Units or X step, depending on Type (see GRID_TYPE for
509                           ///< more details)
510         long      Param2; ///< Either Divisor or Y step, depending on Type (see GRID_TYPE for
511                           ///< more details)
512 
513         static bool IsGrid( XNODE* aNode );
514         void        Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
515     };
516 
517 
518     struct GRIDS : PARSER
519     {
520         GRID WorkingGrid;
521         GRID ScreenGrid;             ///< From CADSTAR Help: "There is one Screen Grid, which is
522                                      ///< visible as dots on the screen. You cannot specify your
523                                      ///< own name for the Screen Grid. The visibility and colour
524                                      ///< of the dots representing the Screen Grid is set up by
525                                      ///< the Highlight category on the Colours dialog.
526                                      ///<
527                                      ///< The type of Screen grid displayed(Lined or Points) is
528                                      ///< set up on the Display dialog within Options(File menu)."
529         std::vector<GRID> UserGrids; ///< List of predefined grids created by the user
530 
531         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
532     };
533 
534 
535     struct SETTINGS : PARSER
536     {
537         UNITS Units;                  ///< Units to display for linear dimensions
538         long  UnitDisplPrecision;     ///< Number of decimal points to display for linear dimensions
539         long  InterlineGap;           ///< For CADSTAR font only, distance between lines of text,
540                                       ///< expressed as a percentage of the text height (accepted
541                                       ///< values are 0-100)
542         long BarlineGap;              ///< For CADSTAR font only, distance between top bar and
543                                       ///< character, expressed as a percentage of the text height
544                                       ///< (accepted values are 0-100)
545         bool AllowBarredText = false; ///< Specifies if barring is allowed in the design
546         long AngularPrecision; ///< Number of decimal points to display for angular dimensions
547 
548         LONGPOINT               DesignOrigin;
549         std::pair<POINT, POINT> DesignArea;
550         LONGPOINT               DesignRef; ///< Appears to be 0,0 always
551         LONGPOINT               DesignLimit;
552 
553         bool         ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
554         virtual void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
555     };
556 
557 
558 
559     /**
560      * @brief From CADSTAR Help: "Text Alignment enables you to define the position of an alignment
561      * origin for all text items in CADSTAR. The alignment origin is a point on or within the text
562      * boundary and defines how the text is displayed.
563      *
564      * For example, with an alignment of bottom-right the origin will be positioned at the bottom
565      * right of the text boundary. This makes it easier to right-align several text items
566      * regardless of the length of text displayed.
567      *
568      * Text Alignment applies to all CADSTAR text. [...]
569      *
570      * Note: Unaligned text operates in the way CADSTAR text always has. In most cases this behaves
571      * as Bottom Left alignment, but there are a few exceptions, e.g. pin names. Also unaligned
572      * multiline text has an origin Bottom Left of the first line."
573      *
574      * See also JUSTIFICATION
575      */
576     enum class ALIGNMENT
577     {
578         NO_ALIGNMENT, ///< NO_ALIGNMENT has different meaning depending on the object type
579         TOPLEFT,
580         TOPCENTER,
581         TOPRIGHT,
582         CENTERLEFT,
583         CENTERCENTER,
584         CENTERRIGHT,
585         BOTTOMLEFT,
586         BOTTOMCENTER,
587         BOTTOMRIGHT
588     };
589 
590 
591     static ALIGNMENT ParseAlignment( XNODE* aNode );
592 
593     /**
594      * @brief From CADSTAR Help: "Multi Line Text can also be justified as Left, Centre or Right.
595      * This does not affect the text alignment. Note: Justification of single line text has no
596      * effect."
597      *
598      * This only affects multiline text
599      *
600      * See also ALIGNMENT
601      */
602     enum class JUSTIFICATION
603     {
604         LEFT,
605         CENTER,
606         RIGHT
607     };
608 
609 
610     static JUSTIFICATION ParseJustification( XNODE* aNode );
611 
612     /**
613      * @brief Sets the readability direction of text. From CADSTAR Help: "Horizontal text will
614      * always be displayed from left to right (i.e. never upside down). Vertical text can be set as
615      * readable from either the left or right edge of the design."
616      *
617      * I.e. Vertical text can either be rotated 90 degrees clockwise or 90 degrees anticlockwise from
618      * horizontal. This does not impact vertical text
619      */
620     enum class READABILITY
621     {
622         BOTTOM_TO_TOP, ///< When text is vertical, show it rotated 90 degrees anticlockwise
623         TOP_TO_BOTTOM  ///< When text is vertical, show it rotated 90 degrees clockwise
624     };
625 
626 
627     static READABILITY ParseReadability( XNODE* aNode );
628 
629 
630     enum class ATTROWNER
631     {
632         ALL_ITEMS,
633         AREA,
634         BOARD,
635         COMPONENT,
636         CONNECTION,
637         COPPER,
638         DOCSYMBOL,
639         FIGURE,
640         NET,
641         NETCLASS,
642         PART,            ///< Only library Attributes
643         PART_DEFINITION, ///< Only library Attributes
644         PIN,
645         SIGNALREF,
646         SYMBOL,
647         SYMDEF,
648         TEMPLATE,
649         TESTPOINT
650     };
651 
652 
653     enum class ATTRUSAGE
654     {
655         BOTH,      ///< From CADSTAR Help: Assigned to both Schematic symbols and PCB components,
656                    ///< and displayed on Schematic and PCB designs.
657         COMPONENT, ///< From CADSTAR Help: Assigned to PCB components and displayed on PCB designs
658         PART_DEFINITION, ///< From CADSTAR Help: Assigned to Parts library Definitions and displayed
659                          ///< by the Library searcher
660         PART_LIBRARY,    ///< From CADSTAR Help: Only used by non-Cadstar applications
661         SYMBOL,          ///< From CADSTAR Help: Assigned to Schematic Symbols and displayed on
662                          ///< Schematic Designs
663         UNDEFINED ///< Note: It seems that some attribute have no "ATTRUSAGE" defined. It appears
664                   ///< that the attributes that fall under this category are the ones associated
665                   ///< with the design itself (i.e. not inherited from the library)
666     };
667 
668 
669     struct ATTRIBUTE_LOCATION : PARSER
670     {
671         TEXTCODE_ID   TextCodeID;
672         LAYER_ID      LayerID;
673         POINT         Position;
674         long          OrientAngle = 0;
675         bool          Mirror      = false;
676         bool          Fixed       = false;
677         JUSTIFICATION Justification =
678                 JUSTIFICATION::LEFT; ///< Note: Justification has no effect on single lines of text
679         ALIGNMENT Alignment = ALIGNMENT::
680                 NO_ALIGNMENT; ///< In CADSTAR The default alignment for a TEXT object (when
681                               ///< "(No Alignment()" is selected) Bottom Left of the *first line*.
682                               ///< Note that this is different from BOTTOM_LEFT (which is bottom
683                               ///< left of the whole text block)
684 
685         void         ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext );
686         bool         ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
687         virtual void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
688     };
689 
690 
691     /**
692      * @brief NOTE from CADSTAR help: To convert a Part Definition Attribute into a hyperlink, prefix
693      * the attribute name with "Link "
694      */
695     struct ATTRNAME : PARSER
696     {
697         struct COLUMNORDER : PARSER
698         {
699             long ID;
700             long Order;
701 
702             void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
703         };
704 
705 
706         struct COLUMNWIDTH : PARSER
707         {
708             long ID;
709             long Width;
710 
711             void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
712         };
713 
714         ATTRIBUTE_ID ID;
715         wxString     Name; ///< Parenthesis aren't permitted in user attributes in CADSTAR. Any
716                            ///< Attributes in Parenthesis indicate an internal CADSTAR attribute
717                            ///< Examples: "(PartDescription)" "(PartDefinitionNameStem)",etc.
718                            ///TODO: create a list of all CADSTAR internal attribute names.
719         ATTROWNER AttributeOwner = ATTROWNER::ALL_ITEMS;
720         ATTRUSAGE AttributeUsage = ATTRUSAGE::UNDEFINED;
721         bool      NoTransfer     = false; ///< True="All Design Types", False="Current Design Type"
722                                           ///< "All Design Types" Description from CADSTAR Help:
723                                           ///< "The selected attribute name will be available when
724                                           ///< any design is displayed"
725                                           ///< "Current Design Type" From CADSTAR Help: This
726                                           ///< restricts the availability of the selected attribute
727                                           ///< name to the current design.
728         std::vector<COLUMNORDER> ColumnOrders;
729         std::vector<COLUMNWIDTH> ColumnWidths;
730         bool                     ColumnInvisible = false;
731 
732         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
733     };
734 
735 
736     struct ATTRIBUTE_VALUE : PARSER
737     {
738         ATTRIBUTE_ID AttributeID;
739         wxString     Value;
740         bool         ReadOnly    = false;
741         bool         HasLocation = false; ///< Flag to know if this ATTRIBUTE_VALUE has a location
742                                           ///< i.e. is displayed
743         ATTRIBUTE_LOCATION AttributeLocation;
744 
745         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
746     };
747 
748 
749     /**
750      * @brief Corresponds to CADSTAR "origin". This is used for setting a location of an attribute
751      * e.g. Designator (called Component Name in CADSTAR), Part Name (name of component in the
752      * library), etc. The atom identifier is "TEXTLOC"
753      */
754     struct TEXT_LOCATION : ATTRIBUTE_LOCATION
755     {
TEXT_LOCATIONTEXT_LOCATION756         TEXT_LOCATION()
757         {
758             // The default alignment for TEXT_LOCATION (when "NO_ALIGNMENT" is selected) is
759             // Bottom left, matching CADSTAR's default behaviour
760             Alignment = ALIGNMENT::BOTTOMLEFT;
761         }
762         ATTRIBUTE_ID AttributeID;
763 
764         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
765     };
766 
767 
768     struct CADSTAR_NETCLASS : PARSER
769     {
770         NETCLASS_ID                  ID;
771         wxString                     Name;
772         std::vector<ATTRIBUTE_VALUE> Attributes;
773 
774         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
775     };
776 
777 
778     struct SPCCLASSNAME : PARSER
779     {
780         SPACING_CLASS_ID ID;
781         wxString         Name;
782 
783         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
784     };
785 
786 
787     struct CODEDEFS : PARSER
788     {
789         std::map<LINECODE_ID, LINECODE>          LineCodes;
790         std::map<HATCHCODE_ID, HATCHCODE>        HatchCodes;
791         std::map<TEXTCODE_ID, TEXTCODE>          TextCodes;
792         std::map<ROUTECODE_ID, ROUTECODE>        RouteCodes;
793         std::map<ATTRIBUTE_ID, ATTRNAME>         AttributeNames;
794         std::map<NETCLASS_ID, CADSTAR_NETCLASS>  NetClasses;
795         std::map<SPACING_CLASS_ID, SPCCLASSNAME> SpacingClassNames;
796 
797         bool ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
798     };
799 
800     /**
801      * @brief Corresponds to "Display when" Item property. From CADSTAR
802      *        Help: "This parameter enables you to make the visibility of
803      *        a component outline/area (or an area of component copper, or
804      *        a string of component text) dependent on the current mirror
805      *        status of the component.
806      *
807      *        For example, you may require a string of component text to
808      *        be displayed only when the component is mirrored."
809      */
810     enum class SWAP_RULE
811     {
812         NO_SWAP,        ///< Display when Unmirrored
813         USE_SWAP_LAYER, ///< Display when Mirrored
814         BOTH            ///< Always display (Mirrored and Unmirrored)
815     };
816 
817 
818     static SWAP_RULE ParseSwapRule( XNODE* aNode );
819 
820 
821     struct REUSEBLOCK : PARSER
822     {
823         REUSEBLOCK_ID ID;
824         wxString      Name;
825         wxString FileName; ///< Filename of the reuse block (usually a .pcb). Used for reloading
826         bool     Mirror      = false;
827         long     OrientAngle = 0;
828 
829         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
830     };
831 
832 
833     /**
834      * @brief References an element from a design reuse block
835      */
836     struct REUSEBLOCKREF : PARSER
837     {
838         REUSEBLOCK_ID ReuseBlockID = wxEmptyString;
839         wxString ItemReference = wxEmptyString; ///< For Components, this references the designator
840                                                 ///< in the reuse file.
841                                                 ///< For net elements (such as vias, routes, etc.),
842                                                 ///< coppers and templates, this parameter is blank.
843 
844         bool IsEmpty(); ///< Determines if this is empty (i.e. no design reuse associated)
845         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
846     };
847 
848 
849     struct GROUP : PARSER
850     {
851         GROUP_ID ID;
852         wxString Name;
853         bool     Fixed    = false;
854         bool     Transfer = false;         ///< If true, the group is transferred to PCB
855         GROUP_ID GroupID  = wxEmptyString; ///< If not empty, this GROUP
856                                            ///< is part of another GROUP
857         REUSEBLOCKREF ReuseBlockRef;
858 
859         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
860     };
861 
862 
863     struct FIGURE : PARSER
864     {
865         FIGURE_ID   ID;
866         LINECODE_ID LineCodeID;
867         LAYER_ID    LayerID;
868         SHAPE       Shape; //< Uses the component's coordinate frame if within a component
869                            //< definition, otherwise uses the design's coordinate frame.
870         GROUP_ID      GroupID = wxEmptyString; ///< If not empty, this FIGURE is part of a group
871         REUSEBLOCKREF ReuseBlockRef;
872         SWAP_RULE     SwapRule = SWAP_RULE::BOTH; ///< Only applicable to Figures in Components
873         bool          Fixed    = false;
874         std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues;
875 
876         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
877     };
878 
879 
880     struct TEXT : PARSER
881     {
882         TEXT_ID       ID;
883         wxString      Text; //TODO: Need to lex/parse to identify design fields and hyperlinks
884         TEXTCODE_ID   TextCodeID;
885         LAYER_ID      LayerID;
886         POINT         Position;
887         long          OrientAngle = 0;
888         bool          Mirror      = false;
889         bool          Fixed       = false;
890         SWAP_RULE     SwapRule    = SWAP_RULE::BOTH;
891         JUSTIFICATION Justification =
892                 JUSTIFICATION::LEFT; ///< Note: Justification has no effect on single lines of text
893         ALIGNMENT Alignment = ALIGNMENT::
894                 NO_ALIGNMENT; ///< In CADSTAR The default alignment for a TEXT object (when
895                               ///< "(No Alignment()" is selected) Bottom Left of the *first line*.
896                               ///< Note that this is different from BOTTOM_LEFT (which is bottom
897                               ///< left of the whole text block)
898         GROUP_ID      GroupID = wxEmptyString; ///< If not empty, this FIGURE is part of a group
899         REUSEBLOCKREF ReuseBlockRef;
900 
901         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
902         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext, bool aParseFields );
903     };
904 
905 
906     struct SYMDEF : PARSER
907     {
908         SYMDEF_ID ID;
909         wxString  ReferenceName; ///< This is the name which identifies the symbol in the library
910                                  ///< Multiple components may exist with the same ReferenceName.
911         wxString Alternate;      ///< This is in addition to ReferenceName. It allows defining
912                                  ///< different versions, views etc. of the same basic symbol.
913         POINT Origin;            ///< Origin of the component (this is used as the reference point
914                                  ///< when placing the component in the design)
915         bool Stub = false;       ///< When the CADSTAR Archive file is exported without the
916                                  ///< component library, if components on the board are still
917                                  ///< exported, the Reference and Alternate names will still be
918                                  ///< exported but the content is replaced with a "STUB" atom,
919                                  ///< requiring access to the original library for component
920                                  ///< definition.
921         long Version = UNDEFINED_VALUE; ///< Version is a sequential integer number to identify
922                                         ///< discrepancies between the library and the design.
923 
924         std::map<FIGURE_ID, FIGURE>           Figures;
925         std::map<TEXT_ID, TEXT>               Texts;
926         std::map<ATTRIBUTE_ID, TEXT_LOCATION> TextLocations;     ///< This contains location of
927                                                                  ///< any attributes, including
928                                                                  ///< designator position
929         std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues; ///< These attributes might also
930                                                                  ///< have a location
931 
932         void ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext );
933         bool ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
934     };
935 
936 
937     struct PART : PARSER
938     {
939         enum class PIN_TYPE
940         {
941             UNCOMMITTED,        ///< Uncommitted pin (default)
942             INPUT,              ///< Input pin
943             OUTPUT_OR,          ///< Output pin OR tieable
944             OUTPUT_NOT_OR,      ///< Output pin not OR tieable
945             OUTPUT_NOT_NORM_OR, ///< Output pin not normally OR tieable
946             POWER,              ///< Power pin
947             GROUND,             ///< Ground pin
948             TRISTATE_BIDIR,     ///< Tristate bi-directional driver pin
949             TRISTATE_INPUT,     ///< Tristate input pin
950             TRISTATE_DRIVER     ///< Tristate output pin
951         };
952 
953 
954         static PIN_TYPE GetPinType( XNODE* aNode );
955 
956 
957         struct DEFINITION : PARSER ///< "PARTDEFINITION" node name
958         {
959             struct GATE : PARSER ///< "GATEDEFINITION" node name
960             {
961                 GATE_ID  ID;        ///< Usually "A", "B", "C", etc.
962                 wxString Name;      ///< Symbol name in the symbol library
963                 wxString Alternate; ///< Symbol alternate name in the symbol library
964                 long     PinCount;  ///< Number of pins (terminals) in the symbol
965 
966                 void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
967             };
968 
969 
970             struct PIN : PARSER ///< "PARTDEFINITIONPIN" node name
971             {
972                 /**
973                  * @brief Positioning of pin names can be in one of four quadrants
974                 */
975                 enum class POSITION
976                 {
977                     TOP_RIGHT    = 0, ///< Default
978                     TOP_LEFT     = 1,
979                     BOTTOM_LEFT  = 2,
980                     BOTTOM_RIGHT = 3
981                 };
982 
983                 PART_DEFINITION_PIN_ID ID = UNDEFINED_VALUE;
984 
985                 wxString Identifier = wxEmptyString;      ///< This should match a pad identifier
986                                                           ///< in the component footprint
987                                                           ///< subnode="PINIDENTIFIER". It is assumed
988                                                           ///< that this could be empty in earlier
989                                                           ///< versions of CADSTAR
990                 wxString Name = wxEmptyString;            ///< Can be empty. If empty the pin name
991                                                           ///< displayed wil be Identifier
992                                                           ///< (subnode="PINNAME")
993                                                           ///< This seems to be equivalent to "Pin
994                                                           ///< Number" in KiCad.
995                 wxString Label = wxEmptyString;           ///< This Can be empty (subnode=
996                                                           ///< "PINLABEL")
997                                                           ///< From CADSTAR Help: "Pin
998                                                           ///< Labels are an optional replacement
999                                                           ///< for the free text sometimes placed
1000                                                           ///< in schematic symbols. Using Pin
1001                                                           ///< Labels instead has the advantage of
1002                                                           ///< associating each piece of label
1003                                                           ///< text with a particular pin. This
1004                                                           ///< means that the text remains
1005                                                           ///< correctly placed after any Gate and
1006                                                           ///< Pin Swaps are Back Annotated to the
1007                                                           ///< Schematic design."
1008                                                           ///< This seems to be equivalent to "Pin
1009                                                           ///< Name" in KiCad.
1010                 wxString Signal = wxEmptyString;          ///< Usually for Power/Ground pins,
1011                                                           ///< (subnode="PINSIGNAL")
1012                 GATE_ID     TerminalGate;                 ///< (subnode="PINTERM", param0)
1013                 TERMINAL_ID TerminalPin;                  ///< (subnode="PINTERM", param1)
1014                 PIN_TYPE    Type = PIN_TYPE::UNCOMMITTED; ///< subnode="PINTYPE"
1015                 long        Load = UNDEFINED_VALUE;       ///< The electrical current expected on
1016                                                           ///< the pin (It is unclear what the units
1017                                                           ///< are, but only accepted values are
1018                                                           ///< integers) subnode ="PINLOAD"
1019                 POSITION Position =
1020                         POSITION::TOP_RIGHT; ///< The pin names will use these positions when
1021                                              ///< the symbol is added to a schematic design
1022                                              ///< subnode="PINPOSITION"
1023 
1024                 void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1025             };
1026 
1027 
1028             struct PIN_EQUIVALENCE : PARSER ///< "PINEQUIVALENCE" Node name
1029             {
1030                 std::vector<PART_DEFINITION_PIN_ID> PinIDs; ///< All the pins in this vector are
1031                                                             ///< equivalent and can be swapped with
1032                                                             ///< each other
1033 
1034                 void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1035             };
1036 
1037 
1038             struct SWAP_GATE : PARSER ///< "SWAPGATE" Node name (represents an "Element")
1039             {
1040                 std::vector<PART_DEFINITION_PIN_ID> PinIDs; ///< The pins in this vector
1041                                                             ///< describe a "gate"
1042 
1043                 void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1044             };
1045 
1046 
1047             struct SWAP_GROUP : PARSER
1048             {
1049                 wxString GateName =
1050                         wxEmptyString; ///< Optional. If not empty, should match the Name
1051                                        ///< attribute of one of the gates defined in the
1052                                        ///< part definition
1053 
1054                 bool External = false; ///< Determines if this swap group is external (and internal)
1055                                        ///< or internal only. External Gate swapping allows Gates on
1056                                        ///< different components with the same Part Definition to
1057                                        ///< swap with one another.
1058                                        ///<
1059                                        ///< The external swapping groups must be at the root level
1060                                        ///< (i.e. they cannot be contained by other swapping groups)
1061 
1062                 std::vector<SWAP_GATE> SwapGates; ///< Each of the elements in this vector can be
1063                                                   ///< swapped with each other - i.e. *all* of the
1064                                                   ///< pins in each swap gate can be swapped with
1065                                                   ///< *all* in another swap gate defined in this
1066                                                   ///< vector
1067 
1068                 void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1069             };
1070 
1071             wxString Name; ///< This name can be different to the PART name
1072             bool     HidePinNames =
1073                     false; ///< Specifies whether to display the pin names/identifier in
1074                            ///< the schematic symbol or not. E.g. it is useful to display
1075                            ///< pin name information for integrated circuits but less so
1076                            ///< for resistors and capacitors. (subnode HIDEPINNAMES)
1077 
1078             long MaxPinCount =
1079                     UNDEFINED_VALUE; ///< Optional parameter which is used for specifying the number
1080                                      ///< of electrical pins on the PCB component symbol to be
1081                                      ///< used in the  part definition (this should not include
1082                                      ///< mechanical pins for fixing etc.). This value must be less
1083                                      ///< than or equal to than the number of pins on the PCB
1084                                      ///< Component symbol.
1085 
1086             std::map<GATE_ID, GATE>                 GateSymbols;
1087             std::map<PART_DEFINITION_PIN_ID, PIN>   Pins;
1088             std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues; ///< Some attributes are
1089                                                                      ///< defined within the part
1090                                                                      ///< definition, whilst others
1091                                                                      ///< are defined in the part
1092             std::vector<PIN_EQUIVALENCE> PinEquivalences;
1093             std::vector<SWAP_GROUP>      SwapGroups;
1094 
1095             void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1096         };
1097 
1098 
1099         struct PART_PIN : PARSER ///< "PARTPIN" node name
1100         {
1101             PART_PIN_ID ID;
1102             wxString    Name       = wxEmptyString;
1103             PIN_TYPE    Type       = PIN_TYPE::UNCOMMITTED;
1104             wxString    Identifier = wxEmptyString;
1105 
1106             void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1107         };
1108 
1109 
1110         PART_ID                         ID;
1111         wxString                        Name;
1112         long                            Version;
1113         DEFINITION                      Definition;
1114         std::map<PART_PIN_ID, PART_PIN> PartPins; ///< It is unclear why there are two "Pin"
1115                                                   ///< structures in CPA files... PART_PIN seems to
1116                                                   ///< be a reduced version of PART::DEFINITION::PIN
1117                                                   ///< Therefore, PART_PIN is only included for
1118                                                   ///< completeness of the parser, but won't be used
1119 
1120         bool HidePinNames = false; ///< This seems to be a duplicate of DEFINITION::HidePinNames
1121                                    ///< Possibly only used in older file formats?
1122 
1123         std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues; ///< Some attributes are defined
1124                                                                  ///< within the part definition,
1125                                                                  ///< whilst others are defined in
1126                                                                  ///< the part itself
1127 
1128         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1129     };
1130 
1131 
1132     struct PARTS : PARSER
1133     {
1134         std::map<PART_ID, PART> PartDefinitions;
1135 
1136         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1137     };
1138 
1139 
1140     struct NET : PARSER
1141     {
1142         struct JUNCTION : PARSER ///< "JPT" nodename.
1143         {
1144             NETELEMENT_ID ID; ///< First character is "J"
1145             LAYER_ID      LayerID;
1146             POINT         Location;
1147             GROUP_ID      GroupID = wxEmptyString; ///< If not empty, this JUCTION is part of a
1148                                                    ///< group
1149             REUSEBLOCKREF ReuseBlockRef;
1150             bool          Fixed = false;
1151 
1152             void         ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext );
1153             bool         ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
1154             virtual void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1155         };
1156 
1157 
1158         struct CONNECTION : PARSER ///< "CONN" nodename
1159         {
1160             NETELEMENT_ID StartNode;
1161             NETELEMENT_ID EndNode;
1162             ROUTECODE_ID  RouteCodeID;
1163 
1164             bool     Fixed   = false;
1165             bool     Hidden  = false;
1166             GROUP_ID GroupID = wxEmptyString; ///< If not empty, this connection is part of a group
1167             REUSEBLOCKREF ReuseBlockRef;
1168 
1169             std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues; ///< It is possible to add
1170                                                                      ///< attributes solely to a
1171                                                                      ///< particular connection
1172             void ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext );
1173             bool ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
1174 
~CONNECTIONNET::CONNECTION1175             virtual ~CONNECTION() {}
1176         };
1177 
1178         NET_ID       ID;
1179         ROUTECODE_ID RouteCodeID = wxEmptyString;   ///< "NETCODE" subnode
1180         long         SignalNum   = UNDEFINED_VALUE; ///< This is undefined if the net has been
1181                                                     ///< given a name. "SIGNUM" subnode.
1182         wxString Name = wxEmptyString; ///< This is undefined (wxEmptyString) if the net
1183                                        ///< is unnamed. "SIGNAME" subnode
1184         bool Highlight = false;
1185 
1186         std::map<NETELEMENT_ID, JUNCTION>       Junctions;
1187         std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues;
1188 
1189         NETCLASS_ID NetClassID =
1190                 wxEmptyString; ///< The net might not have a net class, in which case it will be
1191                                ///<  wxEmptyString ("NETCLASSREF" subnode)
1192         SPACING_CLASS_ID SpacingClassID =
1193                 wxEmptyString; ///< The net might not have a spacing class, in which case it will
1194                                ///< be wxEmptyString ("SPACINGCLASS" subnode)
1195 
1196         void ParseIdentifiers( XNODE* aNode, PARSER_CONTEXT* aContext );
1197         bool ParseSubNode( XNODE* aChildNode, PARSER_CONTEXT* aContext );
1198     };
1199 
1200 
1201     struct DOCUMENTATION_SYMBOL : PARSER
1202     {
1203         DOCUMENTATION_SYMBOL_ID ID;
1204 
1205         SYMDEF_ID SymdefID; ///< Normally documentation symbols only have TEXT, FIGURE and
1206                             ///< TEXT_LOCATION objects which are all drawn on the "(Undefined)"
1207                             ///< Layer. When used in the design, the user has to specify which
1208                             ///< layer to draw it on.
1209         LAYER_ID LayerID;   ///< Move all objects in the Symdef to this layer.
1210         POINT    Origin;    ///< Origin of the component (this is used as the reference point
1211                             ///< when placing the component in the design)
1212 
1213         GROUP_ID      GroupID = wxEmptyString; ///< If not empty, this component is part of a group
1214         REUSEBLOCKREF ReuseBlockRef;
1215         long          OrientAngle = 0;
1216         bool          Mirror      = false;
1217         bool          Fixed       = false;
1218         READABILITY   Readability = READABILITY::BOTTOM_TO_TOP;
1219 
1220         long ScaleRatioNumerator = 1;   ///< Documentation symbols can be arbitrarily scaled when
1221                                         ///< added to a design
1222         long ScaleRatioDenominator = 1; ///< Documentation symbols can be arbitrarily scaled when
1223                                         ///< added to a design
1224 
1225         std::map<ATTRIBUTE_ID, ATTRIBUTE_VALUE> AttributeValues;
1226 
1227         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1228     };
1229 
1230 
1231     struct DFLTSETTINGS : PARSER
1232     {
1233         COLOR_ID Color;
1234         bool     IsVisible = true;
1235 
1236         void     Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1237     };
1238 
1239 
1240     struct ATTRCOL : PARSER
1241     {
1242         ATTRIBUTE_ID AttributeID;
1243         COLOR_ID     Color;
1244         bool         IsVisible = true;
1245         bool         IsPickable = true;
1246 
1247         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1248     };
1249 
1250 
1251     struct ATTRCOLORS : PARSER
1252     {
1253         DFLTSETTINGS DefaultSettings;
1254         std::map<ATTRIBUTE_ID, ATTRCOL> AttributeColors;
1255 
1256         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1257     };
1258 
1259 
1260     struct PARTNAMECOL : PARSER
1261     {
1262         COLOR_ID Color;
1263         bool     IsVisible = true;
1264         bool     IsPickable = true;
1265 
1266         void Parse( XNODE* aNode, PARSER_CONTEXT* aContext ) override;
1267     };
1268 
1269     ///////////////////////
1270     // HELPER FUNCTIONS: //
1271     ///////////////////////
1272 
1273 
1274     static void InsertAttributeAtEnd( XNODE* aNode, wxString aValue );
1275 
1276     /**
1277      * @brief Reads a CADSTAR Archive file (S-parameter format)
1278      * @param aFileName
1279      * @param aFileTypeIdentifier Identifier of the first node in the file to check against.
1280               E.g. "CADSTARPCB"
1281      * @param aProgressReporter Pointer to a Progress Reporter to report progress to.
1282      * @return XNODE pointing to the top of the tree for further parsing. Each node has the first
1283      *         element as the node's name and subsequent elements as node attributes ("attr0",
1284      *         "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks.
1285      * @throws IO_ERROR
1286      */
1287     static XNODE* LoadArchiveFile( const wxString& aFileName, const wxString& aFileTypeIdentifier,
1288                                    PROGRESS_REPORTER* aProgressReporter = nullptr );
1289 
1290     /**
1291      * @brief
1292      * @param aAttribute
1293      * @return
1294      */
1295     static bool IsValidAttribute( wxXmlAttribute* aAttribute );
1296 
1297     /**
1298      * @brief
1299      * @param aNode
1300      * @param aID
1301      * @param aIsRequired Prevents exception throwing if false.
1302      * @return returns the value (wxString) of attribute "attrX" in aNode where 'X' is aID
1303      * @throws IO_ERROR if attribute does not exist
1304      */
1305     static wxString GetXmlAttributeIDString(
1306             XNODE* aNode, unsigned int aID, bool aIsRequired = true );
1307 
1308     /**
1309      * @brief
1310      * @param aNode
1311      * @param aID
1312      * @param aIsRequired Prevents exception throwing if false.
1313      * @return returns the value (long) of attribute "attrX" in aNode where 'X' is aID
1314      * @throws IO_ERROR if attribute does not exist
1315      */
1316     static long GetXmlAttributeIDLong( XNODE* aNode, unsigned int aID, bool aIsRequired = true );
1317 
1318     /**
1319      * @brief
1320      * @param aNode
1321      * @throw IO_ERROR if a child node was found
1322      */
1323     static void CheckNoChildNodes( XNODE* aNode );
1324 
1325     /**
1326      * @brief
1327      * @param aNode
1328      * @throw IO_ERROR if a node adjacent to aNode was found
1329      */
1330     static void CheckNoNextNodes( XNODE* aNode );
1331 
1332     /**
1333      * @brief
1334      * @param aNode with a child node containing an EVALUE
1335      * @param aValueToParse
1336      * @throw IO_ERROR if unable to parse or node is not an EVALUE
1337      */
1338     static void ParseChildEValue( XNODE* aNode, PARSER_CONTEXT* aContext, EVALUE& aValueToParse );
1339 
1340     /**
1341      * @brief if no children are present, it just returns an empty
1342      *        vector (without throwing an exception)
1343      * @param aNode containing a series of POINT objects
1344      * @param aTestAllChildNodes
1345      * @param aExpectedNumPoints if UNDEFINED_VALUE (i.e. -1), this is check is disabled
1346      * @return std::vector containing all POINT objects
1347      * @throw IO_ERROR if one of the following:
1348      *         - Unable to parse a POINT object
1349      *         - aTestAllChildNodes is true and one of the child nodes is not a valid POINT object
1350      *         - aExpectedNumPoints is non-negative and the number of POINT objects found is different
1351      */
1352     static std::vector<POINT> ParseAllChildPoints( XNODE* aNode, PARSER_CONTEXT* aContext,
1353             bool aTestAllChildNodes = false, int aExpectedNumPoints = UNDEFINED_VALUE );
1354 
1355     /**
1356      * @brief if no children are present, it just returns an empty
1357      *        vector (without throwing an exception)
1358      * @param aNode containing a series of VERTEX objects
1359      * @param aTestAllChildNodes
1360      * @param aExpectedNumPoints if -1, this is check is disabled
1361      * @return std::vector containing all VERTEX objects
1362      * @throw IO_ERROR if one of the following:
1363      *         - Unable to parse a VERTEX object
1364      *         - aTestAllChildNodes is true and one of the child nodes is not a valid VERTEX object
1365      */
1366     static std::vector<VERTEX> ParseAllChildVertices(
1367             XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes = false );
1368 
1369     /**
1370      * @brief if no children are present, it just returns an empty
1371      *        vector (without throwing an exception)
1372      * @param aNode containing a series of CUTOUT objects
1373      * @param aTestAllChildNodes
1374      * @param aExpectedNumPoints if -1, this is check is disabled
1375      * @return std::vector containing all CUTOUT objects
1376      * @throw IO_ERROR if one of the following:
1377      *         - Unable to parse a CUTOUT object
1378      *         - aTestAllChildNodes is true and one of the child nodes is not a valid CUTOUT object
1379      */
1380     static std::vector<CUTOUT> ParseAllChildCutouts(
1381             XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes = false );
1382 
1383     static long GetNumberOfChildNodes( XNODE* aNode );
1384 
1385     static long GetNumberOfStepsForReporting( XNODE*                aRootNode,
1386                                               std::vector<wxString> aSubNodeChildrenToCount );
1387 
1388     /**
1389      * @brief Convert a string with CADSTAR overbar characters to equivalent in KiCad
1390      * @param aCadstarString Input string
1391      * @return KiCad string with overbar characters
1392     */
1393     static wxString HandleTextOverbar( wxString aCadstarString );
1394 
1395     /**
1396      * Corrects the position of a text element that had NO_ALIGNMENT in CADSTAR. Assumes that the
1397      * provided text element has been initialised with a position and orientation.
1398      * @param aKiCadTextItem a Kicad item to correct
1399      */
1400     static void FixTextPositionNoAlignment( EDA_TEXT* aKiCadTextItem );
1401 
generateLibName(const wxString & aRefName,const wxString & aAlternateName)1402     static wxString generateLibName( const wxString& aRefName, const wxString& aAlternateName )
1403     {
1404         return aRefName
1405                + ( ( aAlternateName.size() > 0 ) ? ( wxT( " (" ) + aAlternateName + wxT( ")" ) )
1406                                                  : wxT( "" ) );
1407     }
1408 
1409 
1410 protected:
1411     void checkPoint(); ///< Updates m_progressReporter or throws if user cancelled
1412 
1413     PARSER_CONTEXT     m_context;
1414     PROGRESS_REPORTER* m_progressReporter; // optional; may be nullptr
1415 
1416 
1417 }; // class CADSTAR_ARCHIVE_PARSER
1418 
1419 #endif // CADSTAR_ARCHIVE_PARSER_H_
1420