20 import cStringIO, xml.parsers.expat
21 from gettext
import gettext
as _
47 self.log.error(_(
"unexpected element \"%s\"") % name)
56 self.log.error(_(
"unexpected character data \"%s\"") % s)
65 return NullHandler.start_element(self, name, attributes)
67 self.text.append(
'\n')
71 self.text.append(data.replace(
'\\',
'\\\\'))
74 self.text.append(
'\\_')
77 def __init__(self, log, rev, attached_to, data, attribute_name):
83 if attribute_name
is not None:
84 self.text.append(
'%s=' % attribute_name)
88 self.text.append(
'\n')
92 self.text.append(
'\\_')
95 return NullHandler.start_element(self, name, attributes)
98 self.text.append(data.replace(
'\\',
'\\\\'))
101 self.data.text =
''.join(self.
text).
encode(
'utf-8')
102 ob = self.rev.add_object(self.
data)
104 self.rev.relocate_object(ob, self.
attached_to,
None)
115 return NullHandler.start_element(self, name, attributes)
117 self.fragments.append(
'\n')
122 self.fragments.append(data.encode())
123 except UnicodeEncodeError:
124 self.log.error(_(
"non-ASCII character in path data"))
127 self.data.pathdata =
''.join(self.
fragments)
128 self.rev.add_object(self.
data)
132 if angle != 0
and angle != 90
and angle != 180
and angle != 270:
144 if name ==
'text' or name ==
'attribute':
145 is_attribute = name ==
'attribute'
147 x = self.c.parse_attribute(
148 attributes,
'x',
None,
149 self.c.parse,
'X coordinate'),
150 y = self.c.parse_attribute(
151 attributes,
'y',
None,
152 self.c.parse,
'Y coordinate'),
153 color = self.c.parse_attribute(
155 5
if is_attribute
else 9,
156 ENUM_COLOR.index,
'color'),
157 text_size = self.c.parse_attribute(
158 attributes,
'size',
None,
160 visibility = self.c.parse_attribute(
161 attributes,
'visible',
None if is_attribute
else 1,
162 ENUM_BOOLEAN.index,
'text visibility'),
163 show_name_value = self.c.parse_attribute(
164 attributes,
'show',
None if is_attribute
else 0,
165 ENUM_SHOW_NAME_VALUE.index,
'show name/value value'),
166 angle = self.c.parse_attribute(
167 attributes,
'angle', 0,
168 parse_angle,
'angle'),
169 alignment = self.c.parse_attribute(
170 attributes,
'alignment', 0,
171 ENUM_ALIGNMENT.index,
'alignment'))
174 name = attributes.pop(
'name')
176 self.c.log.error(_(
"attribute name not specified"))
184 self.c.log.error(_(
"non-text element can't be attached"))
190 x = self.c.parse_attribute(
191 attributes,
'x',
None,
192 self.c.parse,
'X coordinate'),
193 y = self.c.parse_attribute(
194 attributes,
'y',
None,
195 self.c.parse,
'Y coordinate'),
196 radius = self.c.parse_attribute(
197 attributes,
'radius',
None,
198 self.c.parse,
'radius'),
199 startangle = self.c.parse_attribute(
200 attributes,
'startangle',
None,
202 sweepangle = self.c.parse_attribute(
203 attributes,
'sweepangle',
None,
205 color = self.c.parse_attribute(
206 attributes,
'color', 3,
207 ENUM_COLOR.index,
'color'),
208 line = self.c.parse_line(attributes)))
214 x = self.c.parse_attribute(
215 attributes,
'x',
None,
216 self.c.parse,
'X coordinate'),
217 y = self.c.parse_attribute(
218 attributes,
'y',
None,
219 self.c.parse,
'Y coordinate'),
220 width = self.c.parse_attribute(
221 attributes,
'width',
None,
222 self.c.parse,
'width'),
223 height = self.c.parse_attribute(
224 attributes,
'height',
None,
225 self.c.parse,
'height'),
226 color = self.c.parse_attribute(
227 attributes,
'color', 3,
228 ENUM_COLOR.index,
'color'),
229 line = self.c.parse_line(attributes),
230 fill = self.c.parse_fill(attributes)))
236 x = self.c.parse_attribute(
237 attributes,
'x',
None,
238 self.c.parse,
'X coordinate'),
239 y = self.c.parse_attribute(
240 attributes,
'y',
None,
241 self.c.parse,
'Y coordinate'),
242 radius = self.c.parse_attribute(
243 attributes,
'radius',
None,
244 self.c.parse,
'radius'),
245 color = self.c.parse_attribute(
246 attributes,
'color', 3,
247 ENUM_COLOR.index,
'color'),
248 line = self.c.parse_line(attributes),
249 fill = self.c.parse_fill(attributes)))
252 if name ==
'component':
253 ob = self.rev.add_object(
255 x = self.c.parse_attribute(
256 attributes,
'x',
None,
257 self.c.parse,
'X coordinate'),
258 y = self.c.parse_attribute(
259 attributes,
'y',
None,
260 self.c.parse,
'Y coordinate'),
261 selectable = self.c.parse_attribute(
262 attributes,
'selectable',
True,
263 ENUM_BOOLEAN.index,
'selectability'),
264 angle = self.c.parse_attribute(
265 attributes,
'angle', 0,
266 parse_angle,
'angle'),
267 mirror = self.c.parse_attribute(
268 attributes,
'mirror',
False,
269 ENUM_BOOLEAN.index,
'mirror flag')))
271 symbol_id = attributes.pop(
'symbol')
273 self.c.log.error(_(
"symbol not specified"))
276 self.c.log.error(_(
"symbol id can't be empty"))
278 self.c.symbol_refs.append(
279 (self.
rev, ob, symbol_id, self.c.log.lineno))
284 x0 = self.c.parse_attribute(attributes,
'x0',
None,
285 self.c.parse,
'first X coordinate')
286 y0 = self.c.parse_attribute(attributes,
'y0',
None,
287 self.c.parse,
'first Y coordinate')
288 x1 = self.c.parse_attribute(attributes,
'x1',
None,
289 self.c.parse,
'second X coordinate')
290 y1 = self.c.parse_attribute(attributes,
'y1',
None,
291 self.c.parse,
'second Y coordinate')
294 x = x0, y = y0, width = x1 - x0, height = y1 - y0,
295 color = self.c.parse_attribute(
296 attributes,
'color', 3,
297 ENUM_COLOR.index,
'color'),
298 line = self.c.parse_line(attributes)))
301 if name ==
'net' or name ==
'pin':
302 is_pin = name ==
'pin'
303 is_bus = self.c.parse_attribute(attributes,
'type',
False,
304 ENUM_NETTYPE.index,
'net/pin type')
307 is_inverted = self.c.parse_attribute(
308 attributes,
'inverted',
False,
309 ENUM_BOOLEAN.index,
'invertedness')
317 x0 = self.c.parse_attribute(attributes,
'x0',
None,
318 self.c.parse,
'first X coordinate')
319 y0 = self.c.parse_attribute(attributes,
'y0',
None,
320 self.c.parse,
'first Y coordinate')
321 x1 = self.c.parse_attribute(attributes,
'x1',
None,
322 self.c.parse,
'second X coordinate')
323 y1 = self.c.parse_attribute(attributes,
'y1',
None,
324 self.c.parse,
'second Y coordinate')
325 ob = self.rev.add_object(
327 x = x0, y = y0, width = x1 - x0, height = y1 - y0,
328 color = self.c.parse_attribute(
329 attributes,
'color', default_color,
330 ENUM_COLOR.index,
'color'),
333 is_inverted = is_inverted))
338 color = self.c.parse_attribute(attributes,
'color', 3,
339 ENUM_COLOR.index,
'color'),
340 line = self.c.parse_line(attributes),
341 fill = self.c.parse_fill(attributes)))
343 if name ==
'picture':
344 ob = self.rev.add_object(
346 x = self.c.parse_attribute(
347 attributes,
'x',
None,
348 self.c.parse,
'X coordinate'),
349 y = self.c.parse_attribute(
350 attributes,
'y',
None,
351 self.c.parse,
'Y coordinate'),
352 width = self.c.parse_attribute(
353 attributes,
'width',
None,
354 self.c.parse,
'width'),
355 height = self.c.parse_attribute(
356 attributes,
'height',
None,
357 self.c.parse,
'height'),
358 angle = self.c.parse_attribute(
359 attributes,
'angle', 0,
360 parse_angle,
'angle'),
361 mirror = self.c.parse_attribute(
362 attributes,
'mirrored',
False,
363 ENUM_BOOLEAN.index,
'mirror flag'),
366 pixmap_id = attributes.pop(
'pixmap')
368 self.c.log.error(_(
"pixmap not specified"))
371 self.c.log.error(_(
"pixmap id can't be empty"))
373 self.c.pixmap_refs.append(
374 (self.
rev, ob, pixmap_id, self.c.log.lineno))
378 self.c.log.error(_(
"unexpected element \"%s\"") % name)
386 self.
f = cStringIO.StringIO()
396 self.log.error(_(
"base64 decoding error"))
399 self.pixmap.data = data
400 elif data != self.pixmap.data:
401 self.log.warn(_(
"contents of pixmap file \"%s\" don't match "
402 "embedded data") % self.pixmap.filename)
426 if default
is not None:
428 self.log.error(_(
"%s not specified") % msg_fragment)
432 except (KeyError, ValueError):
433 self.log.error(_(
"invalid %s \"%s\"") % (msg_fragment, x))
436 return 0.
if processor == self.
parse else 0
441 attributes,
'linewidth', 0, self.
parse,
'line width')
443 attributes,
'capstyle', 0, ENUM_CAPSTYLE.index,
'cap style')
445 attributes,
'dashstyle', 0, ENUM_DASHSTYLE.index,
'dash style')
446 if line.dash_style != 0
and line.dash_style != 1:
448 attributes,
'dashlength',
None, self.
parse,
'dash length')
450 line.dash_length = -1
451 if line.dash_style != 0:
453 attributes,
'dashspace',
None, self.
parse,
'dash space')
461 attributes,
'filltype', 0, ENUM_FILLTYPE.index,
'fill type')
462 if fill.type == 2
or fill.type == 3:
464 attributes,
'fillwidth',
None, self.
parse,
'fill width')
466 attributes,
'angle0',
None, int,
'first fill angle')
468 attributes,
'pitch0',
None, self.
parse,
'first fill pitch')
475 attributes,
'angle1',
None, int,
'second fill angle')
477 attributes,
'pitch1',
None, self.
parse,
'second fill pitch')
491 if name ==
'content':
493 self.c.log.error(_(
"duplicate content tag"))
500 mode = attributes.pop(
'mode')
502 self.c.log.error(_(
"symbol mode not specified"))
504 if mode ==
'omitted':
507 elif mode ==
'referenced':
510 elif mode ==
'embedded':
514 self.c.log.error(_(
"invalid symbol mode \"%s\"") % mode)
518 name = attributes.pop(
'name')
521 self.c.log.error(_(
"symbol name not specified"))
527 symbol = self.c.load_symbol(name, read_symbol)
531 assert not symbol.embedded
533 symbol_id = attributes.pop(
'id')
535 self.c.log.error(_(
"symbol id not specified"))
538 self.c.log.error(_(
"symbol id can't be empty"))
540 if symbol_id
in self.c.ids:
541 self.c.log.error(_(
"duplicate id \"%s\"") % symbol_id)
543 self.c.ids.add(symbol_id)
544 self.c.symbols[symbol_id] = symbol
550 symbol.prim_objs = reh.rev
555 mode = attributes.pop(
'mode')
557 self.c.log.error(_(
"pixmap mode not specified"))
559 if mode ==
'omitted':
562 elif mode ==
'referenced':
565 elif mode ==
'embedded':
569 self.c.log.error(_(
"invalid pixmap mode \"%s\"") % mode)
573 name = attributes.pop(
'name')
576 self.c.log.error(_(
"pixmap name not specified"))
582 pixmap = self.c.load_pixmap(name, read_pixmap)
586 assert not pixmap.embedded
588 pixmap_id = attributes.pop(
'id')
590 self.c.log.error(_(
"pixmap id not specified"))
593 self.c.log.error(_(
"pixmap id can't be empty"))
595 if pixmap_id
in self.c.ids:
596 self.c.log.error(_(
"duplicate id \"%s\"") % pixmap_id)
598 self.c.ids.add(pixmap_id)
599 self.c.pixmaps[pixmap_id] = pixmap
605 self.c.log.error(_(
"unexpected element \"%s\"") % name)
610 self.c.log.error(_(
"content missing"))
613 context =
LoadContext(log, load_symbol, load_pixmap)
616 def start_root_element(name, attributes):
617 if name !=
'symbol' and name !=
'schematic':
618 log.error(_(
"invalid root element \"%s\"") % name)
621 for feature
in attributes.pop(
'file-format-features',
'').split(
' '):
624 if feature ==
'experimental':
626 elif feature ==
'hybridnum':
627 if context.use_hybridnum:
628 log.error(_(
"duplicate file format feature"))
629 context.use_hybridnum =
True
631 log.error(_(
"unsupported file format feature \"%s\"")
638 for rev, ob, symbol_id, lineno
in context.symbol_refs:
639 if symbol_id
not in context.symbols:
641 log.error(_(
"undefined symbol \"%s\"") % symbol_id)
643 data = rev.get_object_data(ob)
644 data.symbol = context.symbols[symbol_id]
645 rev.set_object_data(ob, data)
647 for rev, ob, pixmap_id, lineno
in context.pixmap_refs:
648 if pixmap_id
not in context.pixmaps:
650 log.error(_(
"undefined pixmap \"%s\"") % pixmap_id)
652 data = rev.get_object_data(ob)
653 data.pixmap = context.pixmaps[pixmap_id]
654 rev.set_object_data(ob, data)
661 def strip_namespace(name, ignore_errors):
663 pos = name.index(NSSEP)
665 if not ignore_errors:
666 log.error(_(
"element name \"%s\" without namespace") % name)
669 if name[:pos] != namespace
and not ignore_errors:
670 log.error(_(
"invalid namespace \"%s\"") % name[:pos])
673 return name[pos + 1:]
675 def StartElementHandler(name, attributes):
676 log.lineno = p.CurrentLineNumber - 1
677 name = strip_namespace(name,
False)
681 new_handler = stack[-1].start_element(name, attributes)
683 new_handler = start_root_element(name, attributes)
684 stack.append(new_handler)
686 if attributes
and not isinstance(new_handler, VoidHandler):
687 log.error(_(
"unexpected attribute(s) %s") % _(
", ").join(
688 _(
"\"%s\"") % attr
for attr
in sorted(attributes)))
690 def EndElementHandler(name):
691 log.lineno = p.CurrentLineNumber - 1
692 name = strip_namespace(name,
True)
693 stack.pop().end_element(name)
695 def CharacterDataHandler(data):
696 log.lineno = p.CurrentLineNumber - 1
697 stack[-1].character_data(data)
699 def StartDoctypeDeclHandler(doctype_name, system_id, public_id,
700 has_internal_subset):
701 log.lineno = p.CurrentLineNumber - 1
702 log.error(_(
"unexpected XML document type declaration"))
704 def ElementDeclHandler(name, model):
705 log.lineno = p.CurrentLineNumber - 1
706 log.error(_(
"unexpected XML element type declaration"))
708 def AttlistDeclHandler(elname, attname, type, default, required):
709 log.lineno = p.CurrentLineNumber - 1
710 log.error(_(
"unexpected XML element type attribute declaration"))
712 def ProcessingInstructionHandler(target, data):
713 log.lineno = p.CurrentLineNumber - 1
714 log.error(_(
"unexpected XML processing instruction"))
716 def UnparsedEntityDeclHandler(entity_name, base, system_id, public_id,
718 log.lineno = p.CurrentLineNumber - 1
719 log.error(_(
"unexpected XML unparsed entity declaration"))
721 def EntityDeclHandler(entity_name, is_parameter_entity, value, base,
722 system_id, public_id, notation_name):
723 log.lineno = p.CurrentLineNumber - 1
724 log.error(_(
"unexpected XML entity declaration"))
726 def NotationDeclHandler(notation_name, base, system_id, public_id):
727 log.lineno = p.CurrentLineNumber - 1
728 log.error(_(
"unexpected XML notation declaration"))
730 def StartCdataSectionHandler():
731 log.lineno = p.CurrentLineNumber - 1
732 log.error(_(
"unexpected XML CDATA section"))
734 def DefaultHandler(data):
735 log.lineno = p.CurrentLineNumber - 1
736 log.error(_(
"unexpected characters in XML document"))
738 def NotStandaloneHandler():
739 log.lineno = p.CurrentLineNumber - 1
740 log.error(_(
"XML document hasn't been declared as standalone"))
742 def ExternalEntityRefHandler(context, base, systemId, publicId):
743 log.lineno = p.CurrentLineNumber - 1
744 log.error(_(
"unexpected reference to external XML entity"))
746 p = xml.parsers.expat.ParserCreate(namespace_separator =
'!')
748 p.XmlDeclHandler =
None
749 p.StartDoctypeDeclHandler = StartDoctypeDeclHandler
750 p.EndDoctypeDeclHandler =
None
751 p.ElementDeclHandler = ElementDeclHandler
752 p.AttlistDeclHandler = AttlistDeclHandler
753 p.StartElementHandler = StartElementHandler
754 p.EndElementHandler = EndElementHandler
755 p.ProcessingInstructionHandler = ProcessingInstructionHandler
756 p.CharacterDataHandler = CharacterDataHandler
757 p.UnparsedEntityDeclHandler = UnparsedEntityDeclHandler
758 p.EntityDeclHandler = EntityDeclHandler
759 p.NotationDeclHandler = NotationDeclHandler
760 p.StartNamespaceDeclHandler =
None
761 p.EndNamespaceDeclHandler =
None
762 p.CommentHandler =
None
763 p.StartCdataSectionHandler = StartCdataSectionHandler
764 p.EndCdataSectionHandler =
None
765 p.DefaultHandler = DefaultHandler
766 p.DefaultHandlerExpand =
None
767 p.NotStandaloneHandler = NotStandaloneHandler
768 p.ExternalEntityRefHandler = ExternalEntityRefHandler
772 except xml.parsers.expat.ExpatError
as e:
773 log.lineno = e.lineno - 1
774 log.error(_(
"%s") % e)
Reading and writing base64-encoded data.
Schematic net segment, bus segment, or pin.
def encode
Write a binary string to a file in base64 representation.
Raised when reading invalid or unterminated base64-encoded data.
High-level revision proxy class.
def parse
Convert a hybrid string representation to a floating-point number.
def decode
Read a string in base64 representation from a file.
Schematic text or attribute.
High-level proxy classes for the storage backend.
A particular state of the contents of a file.
Referenced symbols and pixmaps.
def parse
Convert a fixed-point string representation to an integer.
Hybrid fixed-/floating-point numbers.