You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1079 lines
34 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
  6. * Copyright (C) 2017 CERN.
  7. * @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <eagle_parser.h>
  27. #include <functional>
  28. #include <sstream>
  29. #include <iomanip>
  30. #include <cstdio>
  31. constexpr auto DEFAULT_ALIGNMENT = ETEXT::BOTTOM_LEFT;
  32. wxString escapeName( const wxString& aNetName )
  33. {
  34. wxString ret( aNetName );
  35. ret.Replace( "~", "~~" );
  36. ret.Replace( "!", "~" );
  37. return ret;
  38. }
  39. template<> template<>
  40. OPTIONAL_XML_ATTRIBUTE<wxString>::OPTIONAL_XML_ATTRIBUTE( wxString aData )
  41. {
  42. m_isAvailable = !aData.IsEmpty();
  43. if( m_isAvailable )
  44. Set( aData );
  45. }
  46. ECOORD::ECOORD( const wxString& aValue, enum ECOORD::EAGLE_UNIT aUnit )
  47. {
  48. // this array is used to adjust the fraction part value basing on the number of digits in the fraction
  49. constexpr int DIVIDERS[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
  50. constexpr unsigned int DIVIDERS_MAX_IDX = sizeof( DIVIDERS ) / sizeof( DIVIDERS[0] ) - 1;
  51. int integer, fraction, pre_fraction, post_fraction;
  52. // the following check is needed to handle correctly negative fractions where the integer part == 0
  53. bool negative = ( aValue[0] == '-' );
  54. // %n is used to find out how many digits contains the fraction part, e.g. 0.001 contains 3 digits
  55. int ret = sscanf( aValue.c_str(), "%d.%n%d%n", &integer, &pre_fraction, &fraction, &post_fraction );
  56. if( ret == 0 )
  57. throw XML_PARSER_ERROR( "Invalid coordinate" );
  58. // process the integer part
  59. value = ConvertToNm( integer, aUnit );
  60. // process the fraction part
  61. if( ret == 2 )
  62. {
  63. int digits = post_fraction - pre_fraction;
  64. // adjust the number of digits if necessary as we cannot handle anything smaller than nanometers (rounding)
  65. if( (unsigned) digits > DIVIDERS_MAX_IDX )
  66. {
  67. int diff = digits - DIVIDERS_MAX_IDX;
  68. digits = DIVIDERS_MAX_IDX;
  69. fraction /= DIVIDERS[diff];
  70. }
  71. int frac_value = ConvertToNm( fraction, aUnit ) / DIVIDERS[digits];
  72. // keep the sign in mind
  73. value = negative ? value - frac_value : value + frac_value;
  74. }
  75. }
  76. long long int ECOORD::ConvertToNm( int aValue, enum EAGLE_UNIT aUnit )
  77. {
  78. long long int ret;
  79. switch( aUnit )
  80. {
  81. default:
  82. case EU_NM: ret = aValue; break;
  83. case EU_MM: ret = (long long) aValue * 1000000; break;
  84. case EU_INCH: ret = (long long) aValue * 25400000; break;
  85. case EU_MIL: ret = (long long) aValue * 25400; break;
  86. }
  87. if( ( ret > 0 ) != ( aValue > 0 ) )
  88. wxLogError( _( "Invalid size %lld: too large" ), aValue );
  89. return ret;
  90. }
  91. // Template specializations below parse wxString to the used types:
  92. // - wxString (preferred)
  93. // - string
  94. // - double
  95. // - int
  96. // - bool
  97. // - EROT
  98. // - ECOORD
  99. template <>
  100. wxString Convert<wxString>( const wxString& aValue )
  101. {
  102. return aValue;
  103. }
  104. template <>
  105. std::string Convert<std::string>( const wxString& aValue )
  106. {
  107. return std::string( aValue.ToUTF8() );
  108. }
  109. template <>
  110. double Convert<double>( const wxString& aValue )
  111. {
  112. double value;
  113. if( aValue.ToDouble( &value ) )
  114. return value;
  115. else
  116. throw XML_PARSER_ERROR( "Conversion to double failed. Original value: '" +
  117. aValue.ToStdString() + "'." );
  118. }
  119. template <>
  120. int Convert<int>( const wxString& aValue )
  121. {
  122. if( aValue.IsEmpty() )
  123. throw XML_PARSER_ERROR( "Conversion to int failed. Original value is empty." );
  124. return wxAtoi( aValue );
  125. }
  126. template <>
  127. bool Convert<bool>( const wxString& aValue )
  128. {
  129. if( aValue != "yes" && aValue != "no" )
  130. throw XML_PARSER_ERROR( "Conversion to bool failed. Original value, '" +
  131. aValue.ToStdString() +
  132. "', is neither 'yes' nor 'no'." );
  133. return aValue == "yes";
  134. }
  135. /// parse an Eagle XML "rot" field. Unfortunately the DTD seems not to explain
  136. /// this format very well. [S][M]R<degrees>. Examples: "R90", "MR180", "SR180"
  137. template<>
  138. EROT Convert<EROT>( const wxString& aRot )
  139. {
  140. EROT value;
  141. value.spin = aRot.find( 'S' ) != aRot.npos;
  142. value.mirror = aRot.find( 'M' ) != aRot.npos;
  143. value.degrees = strtod( aRot.c_str()
  144. + 1 // skip leading 'R'
  145. + int( value.spin ) // skip optional leading 'S'
  146. + int( value.mirror ), // skip optional leading 'M'
  147. NULL );
  148. return value;
  149. }
  150. template<>
  151. ECOORD Convert<ECOORD>( const wxString& aCoord )
  152. {
  153. // Eagle uses millimeters as the default unit
  154. return ECOORD( aCoord, ECOORD::EAGLE_UNIT::EU_MM );
  155. }
  156. /**
  157. * Function parseRequiredAttribute
  158. * parsese the aAttribute of the XML node aNode.
  159. * @param aNode is the node whose attribute will be parsed.
  160. * @param aAttribute is the attribute that will be parsed.
  161. * @throw XML_PARSER_ERROR - exception thrown if the required attribute is missing
  162. * @return T - the attributed parsed as the specified type.
  163. */
  164. template<typename T>
  165. T parseRequiredAttribute( wxXmlNode* aNode, const wxString& aAttribute )
  166. {
  167. wxString value;
  168. if( aNode->GetAttribute( aAttribute, &value ) )
  169. return Convert<T>( value );
  170. else
  171. throw XML_PARSER_ERROR( "The required attribute " + aAttribute + " is missing." );
  172. }
  173. /**
  174. * Function parseOptionalAttribute
  175. * parses the aAttribute of the XML node aNode.
  176. * @param aNode is the node whose attribute will be parsed.
  177. * @param aAttribute is the attribute that will be parsed.
  178. * @return OPTIONAL_XML_ATTRIBUTE<T> - an optional XML attribute, parsed as the specified type if
  179. * found.
  180. */
  181. template<typename T>
  182. OPTIONAL_XML_ATTRIBUTE<T> parseOptionalAttribute( wxXmlNode* aNode, const wxString& aAttribute )
  183. {
  184. return OPTIONAL_XML_ATTRIBUTE<T>( aNode->GetAttribute( aAttribute ) );
  185. }
  186. NODE_MAP MapChildren( wxXmlNode* aCurrentNode )
  187. {
  188. // Map node_name -> node_pointer
  189. NODE_MAP nodesMap;
  190. // Loop through all children mapping them in nodesMap
  191. if( aCurrentNode )
  192. aCurrentNode = aCurrentNode->GetChildren();
  193. while( aCurrentNode )
  194. {
  195. // Create a new pair in the map
  196. // key: current node name
  197. // value: current node pointer
  198. nodesMap[aCurrentNode->GetName()] = aCurrentNode;
  199. // Get next child
  200. aCurrentNode = aCurrentNode->GetNext();
  201. }
  202. return nodesMap;
  203. }
  204. timestamp_t EagleTimeStamp( wxXmlNode* aTree )
  205. {
  206. // in this case from a unique tree memory location
  207. return (timestamp_t) reinterpret_cast<uintptr_t>( aTree );
  208. }
  209. timestamp_t EagleModuleTstamp( const wxString& aName, const wxString& aValue, int aUnit )
  210. {
  211. std::size_t h1 = std::hash<wxString>{}( aName );
  212. std::size_t h2 = std::hash<wxString>{}( aValue );
  213. std::size_t h3 = std::hash<int>{}( aUnit );
  214. return (timestamp_t)( h1 ^ (h2 << 1) ^ (h3 << 2) );
  215. }
  216. wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAngle )
  217. {
  218. // Eagle give us start and end.
  219. // S_ARC wants start to give the center, and end to give the start.
  220. double dx = aEnd.x - aStart.x, dy = aEnd.y - aStart.y;
  221. wxPoint mid = ( aStart + aEnd ) / 2;
  222. double dlen = sqrt( dx*dx + dy*dy );
  223. if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
  224. {
  225. THROW_IO_ERROR(
  226. wxString::Format( _( "Invalid Arc with radius %f and angle %f" ), dlen, aAngle ) );
  227. }
  228. double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
  229. wxPoint center(
  230. mid.x + dist * ( dy / dlen ),
  231. mid.y - dist * ( dx / dlen )
  232. );
  233. return center;
  234. }
  235. static int parseAlignment( const wxString& aAlignment )
  236. {
  237. // (bottom-left | bottom-center | bottom-right | center-left |
  238. // center | center-right | top-left | top-center | top-right)
  239. if( aAlignment == "center" )
  240. return ETEXT::CENTER;
  241. else if( aAlignment == "center-right" )
  242. return ETEXT::CENTER_RIGHT;
  243. else if( aAlignment == "top-left" )
  244. return ETEXT::TOP_LEFT;
  245. else if( aAlignment == "top-center" )
  246. return ETEXT::TOP_CENTER;
  247. else if( aAlignment == "top-right" )
  248. return ETEXT::TOP_RIGHT;
  249. else if( aAlignment == "bottom-left" )
  250. return ETEXT::BOTTOM_LEFT;
  251. else if( aAlignment == "bottom-center" )
  252. return ETEXT::BOTTOM_CENTER;
  253. else if( aAlignment == "bottom-right" )
  254. return ETEXT::BOTTOM_RIGHT;
  255. else if( aAlignment == "center-left" )
  256. return ETEXT::CENTER_LEFT;
  257. return DEFAULT_ALIGNMENT;
  258. }
  259. EWIRE::EWIRE( wxXmlNode* aWire )
  260. {
  261. /*
  262. <!ELEMENT wire EMPTY>
  263. <!ATTLIST wire
  264. x1 %Coord; #REQUIRED
  265. y1 %Coord; #REQUIRED
  266. x2 %Coord; #REQUIRED
  267. y2 %Coord; #REQUIRED
  268. width %Dimension; #REQUIRED
  269. layer %Layer; #REQUIRED
  270. extent %Extent; #IMPLIED -- only applicable for airwires --
  271. style %WireStyle; "continuous"
  272. curve %WireCurve; "0"
  273. cap %WireCap; "round" -- only applicable if 'curve' is not zero --
  274. >
  275. */
  276. x1 = parseRequiredAttribute<ECOORD>( aWire, "x1" );
  277. y1 = parseRequiredAttribute<ECOORD>( aWire, "y1" );
  278. x2 = parseRequiredAttribute<ECOORD>( aWire, "x2" );
  279. y2 = parseRequiredAttribute<ECOORD>( aWire, "y2" );
  280. width = parseRequiredAttribute<ECOORD>( aWire, "width" );
  281. layer = parseRequiredAttribute<int>( aWire, "layer" );
  282. curve = parseOptionalAttribute<double>( aWire, "curve" );
  283. opt_wxString s = parseOptionalAttribute<wxString>( aWire, "style" );
  284. if( s == "continuous" )
  285. style = EWIRE::CONTINUOUS;
  286. else if( s == "longdash" )
  287. style = EWIRE::LONGDASH;
  288. else if( s == "shortdash" )
  289. style = EWIRE::SHORTDASH;
  290. else if( s == "dashdot" )
  291. style = EWIRE::DASHDOT;
  292. s = parseOptionalAttribute<wxString>( aWire, "cap" );
  293. if( s == "round" )
  294. cap = EWIRE::ROUND;
  295. else if( s == "flat" )
  296. cap = EWIRE::FLAT;
  297. }
  298. EJUNCTION::EJUNCTION( wxXmlNode* aJunction )
  299. {
  300. /*
  301. <!ELEMENT junction EMPTY>
  302. <!ATTLIST junction
  303. x %Coord; #REQUIRED
  304. y %Coord; #REQUIRED
  305. >
  306. */
  307. x = parseRequiredAttribute<ECOORD>( aJunction, "x" );
  308. y = parseRequiredAttribute<ECOORD>( aJunction, "y" );
  309. }
  310. ELABEL::ELABEL( wxXmlNode* aLabel, const wxString& aNetName )
  311. {
  312. /*
  313. <!ELEMENT label EMPTY>
  314. <!ATTLIST label
  315. x %Coord; #REQUIRED
  316. y %Coord; #REQUIRED
  317. size %Dimension; #REQUIRED
  318. layer %Layer; #REQUIRED
  319. font %TextFont; "proportional"
  320. ratio %Int; "8"
  321. rot %Rotation; "R0"
  322. xref %Bool; "no"
  323. >
  324. */
  325. x = parseRequiredAttribute<ECOORD>( aLabel, "x" );
  326. y = parseRequiredAttribute<ECOORD>( aLabel, "y" );
  327. size = parseRequiredAttribute<ECOORD>( aLabel, "size" );
  328. layer = parseRequiredAttribute<int>( aLabel, "layer" );
  329. rot = parseOptionalAttribute<EROT>( aLabel, "rot" );
  330. xref = parseOptionalAttribute<wxString>( aLabel, "xref" );
  331. netname = aNetName;
  332. }
  333. EVIA::EVIA( wxXmlNode* aVia )
  334. {
  335. /*
  336. <!ELEMENT via EMPTY>
  337. <!ATTLIST via
  338. x %Coord; #REQUIRED
  339. y %Coord; #REQUIRED
  340. extent %Extent; #REQUIRED
  341. drill %Dimension; #REQUIRED
  342. diameter %Dimension; "0"
  343. shape %ViaShape; "round"
  344. alwaysstop %Bool; "no"
  345. >
  346. */
  347. x = parseRequiredAttribute<ECOORD>( aVia, "x" );
  348. y = parseRequiredAttribute<ECOORD>( aVia, "y" );
  349. wxString ext = parseRequiredAttribute<wxString>( aVia, "extent" );
  350. sscanf( ext.c_str(), "%d-%d", &layer_front_most, &layer_back_most );
  351. drill = parseRequiredAttribute<ECOORD>( aVia, "drill" );
  352. diam = parseOptionalAttribute<ECOORD>( aVia, "diameter" );
  353. shape = parseOptionalAttribute<wxString>( aVia, "shape" );
  354. }
  355. ECIRCLE::ECIRCLE( wxXmlNode* aCircle )
  356. {
  357. /*
  358. <!ELEMENT circle EMPTY>
  359. <!ATTLIST circle
  360. x %Coord; #REQUIRED
  361. y %Coord; #REQUIRED
  362. radius %Coord; #REQUIRED
  363. width %Dimension; #REQUIRED
  364. layer %Layer; #REQUIRED
  365. >
  366. */
  367. x = parseRequiredAttribute<ECOORD>( aCircle, "x" );
  368. y = parseRequiredAttribute<ECOORD>( aCircle, "y" );
  369. radius = parseRequiredAttribute<ECOORD>( aCircle, "radius" );
  370. width = parseRequiredAttribute<ECOORD>( aCircle, "width" );
  371. layer = parseRequiredAttribute<int>( aCircle, "layer" );
  372. }
  373. ERECT::ERECT( wxXmlNode* aRect )
  374. {
  375. /*
  376. <!ELEMENT rectangle EMPTY>
  377. <!ATTLIST rectangle
  378. x1 %Coord; #REQUIRED
  379. y1 %Coord; #REQUIRED
  380. x2 %Coord; #REQUIRED
  381. y2 %Coord; #REQUIRED
  382. layer %Layer; #REQUIRED
  383. rot %Rotation; "R0"
  384. >
  385. */
  386. x1 = parseRequiredAttribute<ECOORD>( aRect, "x1" );
  387. y1 = parseRequiredAttribute<ECOORD>( aRect, "y1" );
  388. x2 = parseRequiredAttribute<ECOORD>( aRect, "x2" );
  389. y2 = parseRequiredAttribute<ECOORD>( aRect, "y2" );
  390. layer = parseRequiredAttribute<int>( aRect, "layer" );
  391. rot = parseOptionalAttribute<EROT>( aRect, "rot" );
  392. }
  393. EATTR::EATTR( wxXmlNode* aTree )
  394. {
  395. /*
  396. <!ELEMENT attribute EMPTY>
  397. <!ATTLIST attribute
  398. name %String; #REQUIRED
  399. value %String; #IMPLIED
  400. x %Coord; #IMPLIED
  401. y %Coord; #IMPLIED
  402. size %Dimension; #IMPLIED
  403. layer %Layer; #IMPLIED
  404. font %TextFont; #IMPLIED
  405. ratio %Int; #IMPLIED
  406. rot %Rotation; "R0"
  407. display %AttributeDisplay; "value" -- only in <element> or <instance> context --
  408. constant %Bool; "no" -- only in <device> context --
  409. >
  410. */
  411. name = parseRequiredAttribute<wxString>( aTree, "name" );
  412. value = parseOptionalAttribute<wxString>( aTree, "value" );
  413. x = parseOptionalAttribute<ECOORD>( aTree, "x" );
  414. y = parseOptionalAttribute<ECOORD>( aTree, "y" );
  415. size = parseOptionalAttribute<ECOORD>( aTree, "size" );
  416. // KiCad cannot currently put a TEXTE_MODULE on a different layer than the MODULE
  417. // Eagle can it seems.
  418. layer = parseOptionalAttribute<int>( aTree, "layer" );
  419. ratio = parseOptionalAttribute<double>( aTree, "ratio" );
  420. rot = parseOptionalAttribute<EROT>( aTree, "rot" );
  421. opt_wxString stemp = parseOptionalAttribute<wxString>( aTree, "display" );
  422. // (off | value | name | both)
  423. if( stemp == "off" )
  424. display = EATTR::Off;
  425. else if( stemp == "name" )
  426. display = EATTR::NAME;
  427. else if( stemp == "both" )
  428. display = EATTR::BOTH;
  429. else // "value" is the default
  430. display = EATTR::VALUE;
  431. stemp = parseOptionalAttribute<wxString>( aTree, "align" );
  432. align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
  433. }
  434. EDIMENSION::EDIMENSION( wxXmlNode* aDimension )
  435. {
  436. /*
  437. <!ELEMENT dimension EMPTY>
  438. <!ATTLIST dimension
  439. x1 %Coord; #REQUIRED
  440. y1 %Coord; #REQUIRED
  441. x2 %Coord; #REQUIRED
  442. y2 %Coord; #REQUIRED
  443. x3 %Coord; #REQUIRED
  444. y3 %Coord; #REQUIRED
  445. layer %Layer; #REQUIRED
  446. dtype %DimensionType; "parallel"
  447. >
  448. */
  449. x1 = parseRequiredAttribute<ECOORD>( aDimension, "x1" );
  450. y1 = parseRequiredAttribute<ECOORD>( aDimension, "y1" );
  451. x2 = parseRequiredAttribute<ECOORD>( aDimension, "x2" );
  452. y2 = parseRequiredAttribute<ECOORD>( aDimension, "y2" );
  453. x3 = parseRequiredAttribute<ECOORD>( aDimension, "x3" );
  454. y3 = parseRequiredAttribute<ECOORD>( aDimension, "y3" );
  455. layer = parseRequiredAttribute<int>( aDimension, "layer" );
  456. dimensionType = parseOptionalAttribute<wxString>( aDimension, "dtype" );
  457. }
  458. ETEXT::ETEXT( wxXmlNode* aText )
  459. {
  460. /*
  461. <!ELEMENT text (#PCDATA)>
  462. <!ATTLIST text
  463. x %Coord; #REQUIRED
  464. y %Coord; #REQUIRED
  465. size %Dimension; #REQUIRED
  466. layer %Layer; #REQUIRED
  467. font %TextFont; "proportional"
  468. ratio %Int; "8"
  469. rot %Rotation; "R0"
  470. align %Align; "bottom-left"
  471. >
  472. */
  473. text = aText->GetNodeContent();
  474. x = parseRequiredAttribute<ECOORD>( aText, "x" );
  475. y = parseRequiredAttribute<ECOORD>( aText, "y" );
  476. size = parseRequiredAttribute<ECOORD>( aText, "size" );
  477. layer = parseRequiredAttribute<int>( aText, "layer" );
  478. font = parseOptionalAttribute<wxString>( aText, "font" );
  479. ratio = parseOptionalAttribute<double>( aText, "ratio" );
  480. rot = parseOptionalAttribute<EROT>( aText, "rot" );
  481. opt_wxString stemp = parseOptionalAttribute<wxString>( aText, "align" );
  482. align = stemp ? parseAlignment( *stemp ) : DEFAULT_ALIGNMENT;
  483. }
  484. wxSize ETEXT::ConvertSize() const
  485. {
  486. wxSize textsize;
  487. if( font )
  488. {
  489. const wxString& fontName = font.CGet();
  490. if( fontName == "vector" )
  491. {
  492. textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
  493. }
  494. else if( fontName == "fixed" )
  495. {
  496. textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() * 0.80 );
  497. }
  498. else
  499. {
  500. wxLogDebug( "Invalid font name \"%s\"", fontName );
  501. textsize = wxSize( size.ToSchUnits(), size.ToSchUnits() );
  502. }
  503. }
  504. else
  505. {
  506. textsize = wxSize( size.ToSchUnits() * 0.85, size.ToSchUnits() );
  507. }
  508. return textsize;
  509. }
  510. EPAD_COMMON::EPAD_COMMON( wxXmlNode* aPad )
  511. {
  512. // #REQUIRED says DTD, throw exception if not found
  513. name = parseRequiredAttribute<wxString>( aPad, "name" );
  514. x = parseRequiredAttribute<ECOORD>( aPad, "x" );
  515. y = parseRequiredAttribute<ECOORD>( aPad, "y" );
  516. rot = parseOptionalAttribute<EROT>( aPad, "rot" );
  517. stop = parseOptionalAttribute<bool>( aPad, "stop" );
  518. thermals = parseOptionalAttribute<bool>( aPad, "thermals" );
  519. }
  520. EPAD::EPAD( wxXmlNode* aPad )
  521. : EPAD_COMMON( aPad )
  522. {
  523. /*
  524. <!ELEMENT pad EMPTY>
  525. <!ATTLIST pad
  526. name %String; #REQUIRED
  527. x %Coord; #REQUIRED
  528. y %Coord; #REQUIRED
  529. drill %Dimension; #REQUIRED
  530. diameter %Dimension; "0"
  531. shape %PadShape; "round"
  532. rot %Rotation; "R0"
  533. stop %Bool; "yes"
  534. thermals %Bool; "yes"
  535. first %Bool; "no"
  536. >
  537. */
  538. // #REQUIRED says DTD, throw exception if not found
  539. drill = parseRequiredAttribute<ECOORD>( aPad, "drill" );
  540. // Optional attributes
  541. diameter = parseOptionalAttribute<ECOORD>( aPad, "diameter" );
  542. opt_wxString s = parseOptionalAttribute<wxString>( aPad, "shape" );
  543. // (square | round | octagon | long | offset)
  544. if( s == "square" )
  545. shape = EPAD::SQUARE;
  546. else if( s == "round" )
  547. shape = EPAD::ROUND;
  548. else if( s == "octagon" )
  549. shape = EPAD::OCTAGON;
  550. else if( s == "long" )
  551. shape = EPAD::LONG;
  552. else if( s == "offset" )
  553. shape = EPAD::OFFSET;
  554. first = parseOptionalAttribute<bool>( aPad, "first" );
  555. }
  556. ESMD::ESMD( wxXmlNode* aSMD )
  557. : EPAD_COMMON( aSMD )
  558. {
  559. /*
  560. <!ATTLIST smd
  561. name %String; #REQUIRED
  562. x %Coord; #REQUIRED
  563. y %Coord; #REQUIRED
  564. dx %Dimension; #REQUIRED
  565. dy %Dimension; #REQUIRED
  566. layer %Layer; #REQUIRED
  567. roundness %Int; "0"
  568. rot %Rotation; "R0"
  569. stop %Bool; "yes"
  570. thermals %Bool; "yes"
  571. cream %Bool; "yes"
  572. >
  573. */
  574. // DTD #REQUIRED, throw exception if not found
  575. dx = parseRequiredAttribute<ECOORD>( aSMD, "dx" );
  576. dy = parseRequiredAttribute<ECOORD>( aSMD, "dy" );
  577. layer = parseRequiredAttribute<int>( aSMD, "layer" );
  578. roundness = parseOptionalAttribute<int>( aSMD, "roundness" );
  579. cream = parseOptionalAttribute<bool>( aSMD, "cream" );
  580. }
  581. EPIN::EPIN( wxXmlNode* aPin )
  582. {
  583. /*
  584. <!ELEMENT pin EMPTY>
  585. <!ATTLIST pin
  586. name %String; #REQUIRED
  587. x %Coord; #REQUIRED
  588. y %Coord; #REQUIRED
  589. visible %PinVisible; "both"
  590. length %PinLength; "long"
  591. direction %PinDirection; "io"
  592. function %PinFunction; "none"
  593. swaplevel %Int; "0"
  594. rot %Rotation; "R0"
  595. >
  596. */
  597. // DTD #REQUIRED, throw exception if not found
  598. name = parseRequiredAttribute<wxString>( aPin, "name" );
  599. x = parseRequiredAttribute<ECOORD>( aPin, "x" );
  600. y = parseRequiredAttribute<ECOORD>( aPin, "y" );
  601. visible = parseOptionalAttribute<wxString>( aPin, "visible" );
  602. length = parseOptionalAttribute<wxString>( aPin, "length" );
  603. direction = parseOptionalAttribute<wxString>( aPin, "direction" );
  604. function = parseOptionalAttribute<wxString>( aPin, "function" );
  605. swaplevel = parseOptionalAttribute<int>( aPin, "swaplevel" );
  606. rot = parseOptionalAttribute<EROT>( aPin, "rot" );
  607. }
  608. EVERTEX::EVERTEX( wxXmlNode* aVertex )
  609. {
  610. /*
  611. <!ELEMENT vertex EMPTY>
  612. <!ATTLIST vertex
  613. x %Coord; #REQUIRED
  614. y %Coord; #REQUIRED
  615. curve %WireCurve; "0" -- the curvature from this vertex to the next one --
  616. >
  617. */
  618. x = parseRequiredAttribute<ECOORD>( aVertex, "x" );
  619. y = parseRequiredAttribute<ECOORD>( aVertex, "y" );
  620. curve = parseOptionalAttribute<double>( aVertex, "curve" );
  621. }
  622. EPOLYGON::EPOLYGON( wxXmlNode* aPolygon )
  623. {
  624. /*
  625. <!ATTLIST polygon
  626. width %Dimension; #REQUIRED
  627. layer %Layer; #REQUIRED
  628. spacing %Dimension; #IMPLIED
  629. pour %PolygonPour; "solid"
  630. isolate %Dimension; #IMPLIED -- only in <signal> or <package> context --
  631. orphans %Bool; "no" -- only in <signal> context --
  632. thermals %Bool; "yes" -- only in <signal> context --
  633. rank %Int; "0" -- 1..6 in <signal> context, 0 or 7 in <package> context --
  634. >
  635. */
  636. width = parseRequiredAttribute<ECOORD>( aPolygon, "width" );
  637. layer = parseRequiredAttribute<int>( aPolygon, "layer" );
  638. spacing = parseOptionalAttribute<ECOORD>( aPolygon, "spacing" );
  639. isolate = parseOptionalAttribute<ECOORD>( aPolygon, "isolate" );
  640. opt_wxString s = parseOptionalAttribute<wxString>( aPolygon, "pour" );
  641. // default pour to solid fill
  642. pour = EPOLYGON::SOLID;
  643. // (solid | hatch | cutout)
  644. if( s == "hatch" )
  645. pour = EPOLYGON::HATCH;
  646. else if( s == "cutout" )
  647. pour = EPOLYGON::CUTOUT;
  648. orphans = parseOptionalAttribute<bool>( aPolygon, "orphans" );
  649. thermals = parseOptionalAttribute<bool>( aPolygon, "thermals" );
  650. rank = parseOptionalAttribute<int>( aPolygon, "rank" );
  651. }
  652. EHOLE::EHOLE( wxXmlNode* aHole )
  653. {
  654. /*
  655. <!ELEMENT hole EMPTY>
  656. <!ATTLIST hole
  657. x %Coord; #REQUIRED
  658. y %Coord; #REQUIRED
  659. drill %Dimension; #REQUIRED
  660. >
  661. */
  662. // #REQUIRED:
  663. x = parseRequiredAttribute<ECOORD>( aHole, "x" );
  664. y = parseRequiredAttribute<ECOORD>( aHole, "y" );
  665. drill = parseRequiredAttribute<ECOORD>( aHole, "drill" );
  666. }
  667. EELEMENT::EELEMENT( wxXmlNode* aElement )
  668. {
  669. /*
  670. <!ELEMENT element (attribute*, variant*)>
  671. <!ATTLIST element
  672. name %String; #REQUIRED
  673. library %String; #REQUIRED
  674. package %String; #REQUIRED
  675. value %String; #REQUIRED
  676. x %Coord; #REQUIRED
  677. y %Coord; #REQUIRED
  678. locked %Bool; "no"
  679. smashed %Bool; "no"
  680. rot %Rotation; "R0"
  681. >
  682. */
  683. // #REQUIRED
  684. name = parseRequiredAttribute<wxString>( aElement, "name" );
  685. library = parseRequiredAttribute<wxString>( aElement, "library" );
  686. value = parseRequiredAttribute<wxString>( aElement, "value" );
  687. std::string p = parseRequiredAttribute<std::string>( aElement, "package" );
  688. ReplaceIllegalFileNameChars( &p, '_' );
  689. package = wxString::FromUTF8( p.c_str() );
  690. x = parseRequiredAttribute<ECOORD>( aElement, "x" );
  691. y = parseRequiredAttribute<ECOORD>( aElement, "y" );
  692. // optional
  693. locked = parseOptionalAttribute<bool>( aElement, "locked" );
  694. smashed = parseOptionalAttribute<bool>( aElement, "smashed" );
  695. rot = parseOptionalAttribute<EROT>( aElement, "rot" );
  696. }
  697. ELAYER::ELAYER( wxXmlNode* aLayer )
  698. {
  699. /*
  700. <!ELEMENT layer EMPTY>
  701. <!ATTLIST layer
  702. number %Layer; #REQUIRED
  703. name %String; #REQUIRED
  704. color %Int; #REQUIRED
  705. fill %Int; #REQUIRED
  706. visible %Bool; "yes"
  707. active %Bool; "yes"
  708. >
  709. */
  710. number = parseRequiredAttribute<int>( aLayer, "number" );
  711. name = parseRequiredAttribute<wxString>( aLayer, "name" );
  712. color = parseRequiredAttribute<int>( aLayer, "color" );
  713. fill = 1; // Temporary value.
  714. visible = parseOptionalAttribute<bool>( aLayer, "visible" );
  715. active = parseOptionalAttribute<bool>( aLayer, "active" );
  716. }
  717. EPART::EPART( wxXmlNode* aPart )
  718. {
  719. /*
  720. * <!ELEMENT part (attribute*, variant*)>
  721. * <!ATTLIST part
  722. * name %String; #REQUIRED
  723. * library %String; #REQUIRED
  724. * deviceset %String; #REQUIRED
  725. * device %String; #REQUIRED
  726. * technology %String; ""
  727. * value %String; #IMPLIED
  728. * >
  729. */
  730. // #REQUIRED
  731. name = parseRequiredAttribute<wxString>( aPart, "name" );
  732. library = parseRequiredAttribute<wxString>( aPart, "library" );
  733. deviceset = parseRequiredAttribute<wxString>( aPart, "deviceset" );
  734. device = parseRequiredAttribute<wxString>( aPart, "device" );
  735. technology = parseOptionalAttribute<wxString>( aPart, "technology" );
  736. value = parseOptionalAttribute<wxString>( aPart, "value" );
  737. for( auto child = aPart->GetChildren(); child; child = child->GetNext() )
  738. {
  739. if( child->GetName() == "attribute" )
  740. {
  741. std::string aname, avalue;
  742. for( auto x = child->GetAttributes(); x; x = x->GetNext() )
  743. {
  744. if( x->GetName() == "name" )
  745. aname = x->GetValue();
  746. else if( x->GetName() == "value" )
  747. avalue = x->GetValue();
  748. }
  749. if( aname.size() && avalue.size() )
  750. attribute[aname] = avalue;
  751. }
  752. else if( child->GetName() == "variant" )
  753. {
  754. std::string aname, avalue;
  755. for( auto x = child->GetAttributes(); x; x = x->GetNext() )
  756. {
  757. if( x->GetName() == "name" )
  758. aname = x->GetValue();
  759. else if( x->GetName() == "value" )
  760. avalue = x->GetValue();
  761. }
  762. if( aname.size() && avalue.size() )
  763. variant[aname] = avalue;
  764. }
  765. }
  766. }
  767. EINSTANCE::EINSTANCE( wxXmlNode* aInstance )
  768. {
  769. /*
  770. * <!ELEMENT instance (attribute)*>
  771. * <!ATTLIST instance
  772. * part %String; #REQUIRED
  773. * gate %String; #REQUIRED
  774. * x %Coord; #REQUIRED
  775. * y %Coord; #REQUIRED
  776. * smashed %Bool; "no"
  777. * rot %Rotation; "R0"
  778. * >
  779. */
  780. part = parseRequiredAttribute<wxString>( aInstance, "part" );
  781. gate = parseRequiredAttribute<wxString>( aInstance, "gate" );
  782. x = parseRequiredAttribute<ECOORD>( aInstance, "x" );
  783. y = parseRequiredAttribute<ECOORD>( aInstance, "y" );
  784. // optional
  785. smashed = parseOptionalAttribute<bool>( aInstance, "smashed" );
  786. rot = parseOptionalAttribute<EROT>( aInstance, "rot" );
  787. }
  788. EGATE::EGATE( wxXmlNode* aGate )
  789. {
  790. /*
  791. * <!ELEMENT gate EMPTY>
  792. * <!ATTLIST gate
  793. * name %String; #REQUIRED
  794. * symbol %String; #REQUIRED
  795. * x %Coord; #REQUIRED
  796. * y %Coord; #REQUIRED
  797. * addlevel %GateAddLevel; "next"
  798. * swaplevel %Int; "0"
  799. * >
  800. */
  801. name = parseRequiredAttribute<wxString>( aGate, "name" );
  802. symbol = parseRequiredAttribute<wxString>( aGate, "symbol" );
  803. x = parseRequiredAttribute<ECOORD>( aGate, "x" );
  804. y = parseRequiredAttribute<ECOORD>( aGate, "y" );
  805. opt_wxString stemp = parseOptionalAttribute<wxString>( aGate, "addlevel" );
  806. // (off | value | name | both)
  807. if( stemp == "must" )
  808. addlevel = EGATE::MUST;
  809. else if( stemp == "can" )
  810. addlevel = EGATE::CAN;
  811. else if( stemp == "next" )
  812. addlevel = EGATE::NEXT;
  813. else if( stemp == "request" )
  814. addlevel = EGATE::REQUEST;
  815. else if( stemp == "always" )
  816. addlevel = EGATE::ALWAYS;
  817. else
  818. addlevel = EGATE::NEXT;
  819. }
  820. ECONNECT::ECONNECT( wxXmlNode* aConnect )
  821. {
  822. /*
  823. * <!ELEMENT connect EMPTY>
  824. * <!ATTLIST connect
  825. * gate %String; #REQUIRED
  826. * pin %String; #REQUIRED
  827. * pad %String; #REQUIRED
  828. * route %ContactRoute; "all"
  829. * >
  830. */
  831. gate = parseRequiredAttribute<wxString>( aConnect, "gate" );
  832. pin = parseRequiredAttribute<wxString>( aConnect, "pin" );
  833. pad = parseRequiredAttribute<wxString>( aConnect, "pad" );
  834. }
  835. EDEVICE::EDEVICE( wxXmlNode* aDevice )
  836. {
  837. /*
  838. <!ELEMENT device (connects?, technologies?)>
  839. <!ATTLIST device
  840. name %String; ""
  841. package %String; #IMPLIED
  842. >
  843. */
  844. name = parseRequiredAttribute<wxString>( aDevice, "name" );
  845. opt_wxString pack = parseOptionalAttribute<wxString>( aDevice, "package" );
  846. if( pack )
  847. {
  848. std::string p( pack->c_str() );
  849. ReplaceIllegalFileNameChars( &p, '_' );
  850. package.Set( wxString::FromUTF8( p.c_str() ) );
  851. }
  852. NODE_MAP aDeviceChildren = MapChildren( aDevice );
  853. wxXmlNode* connectNode = getChildrenNodes( aDeviceChildren, "connects" );
  854. while( connectNode )
  855. {
  856. connects.push_back( ECONNECT( connectNode ) );
  857. connectNode = connectNode->GetNext();
  858. }
  859. }
  860. EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
  861. {
  862. /*
  863. <!ELEMENT deviceset (description?, gates, devices)>
  864. <!ATTLIST deviceset
  865. name %String; #REQUIRED
  866. prefix %String; ""
  867. uservalue %Bool; "no"
  868. >
  869. */
  870. name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
  871. prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
  872. uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
  873. /* Russell: Parsing of devices and gates moved to sch_eagle_plugin.cpp
  874. *
  875. //TODO: description
  876. NODE_MAP aDeviceSetChildren = MapChildren(aDeviceSet);
  877. wxXmlNode* deviceNode = getChildrenNodes(aDeviceSetChildren, "device");
  878. while(deviceNode){
  879. devices.push_back(EDEVICE(deviceNode));
  880. deviceNode->GetNext();
  881. }
  882. wxXmlNode* gateNode = getChildrenNodes(aDeviceSetChildren, "gate");
  883. while(gateNode){
  884. gates.push_back(EGATE(gateNode));
  885. gateNode->GetNext();
  886. }
  887. */
  888. }