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.

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