123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- # Purpose: manage header section
- # Created: 12.03.2011
- # Copyright (c) 2011-2018, Manfred Moitzi
- # License: MIT License
- from typing import TYPE_CHECKING, Iterable, List, Tuple, KeysView, Any, Iterator
- from collections import OrderedDict
- from ezdxf.lldxf.types import strtag
- from ezdxf.lldxf.tags import group_tags, Tags, DXFTag
- from ezdxf.lldxf.const import DXFStructureError, DXFValueError, DXFKeyError
- from ezdxf.lldxf.validator import header_validator
- from ezdxf.legacy.headervars import VARMAP as VARMAP_R12
- from ezdxf.modern.headervars import VARMAP as VARMAP_R13
- if TYPE_CHECKING:
- from ezdxf.eztypes import TagWriter
- MIN_HEADER_TEXT = """ 0
- SECTION
- 2
- HEADER
- 9
- $ACADVER
- 1
- AC1009
- 9
- $DWGCODEPAGE
- 3
- ANSI_1252
- 9
- $HANDSEED
- 5
- FF
- """
- class CustomVars:
- """
- Custom Properties are stored as string tuples ('CustomTag', 'CustomValue') in a list object.
- Multiple occurrence of the same 'CustomTag' is allowed, but not well supported by the interface.
- """
- def __init__(self):
- self.properties = list() # type: List[Tuple[str, str]]
- def __len__(self) -> int:
- return len(self.properties)
- def __iter__(self) -> Iterable[Tuple[str, str]]:
- return iter(self.properties)
- def clear(self) -> None:
- """ Remove all custom properties.
- """
- self.properties.clear()
- def append(self, tag: str, value: str) -> None:
- # custom properties always stored as strings
- self.properties.append((tag, str(value)))
- def get(self, tag: str, default: str = None):
- """ Get value of first occurrence of 'tag'.
- """
- for key, value in self.properties:
- if key == tag:
- return value
- else:
- return default
- def has_tag(self, tag: str) -> bool:
- return self.get(tag) is not None
- def remove(self, tag: str, all: bool = False) -> None:
- """ Remove first occurrence of 'tag', removes all occurrences if param all is True.
- """
- found_tag = False
- for item in self.properties:
- if item[0] == tag:
- self.properties.remove(item)
- found_tag = True
- if not all:
- return
- if not found_tag:
- raise DXFValueError("Tag '%s' does not exist" % tag)
- def replace(self, tag: str, value: str) -> None:
- """ Replaces the value of the first custom property `tag` by a new `value`.
- """
- properties = self.properties
- for index in range(len(properties)):
- name = properties[index][0]
- if name == tag:
- properties[index] = (name, value)
- return
- raise DXFValueError("Tag '%s' does not exist" % tag)
- def write(self, tagwriter: 'TagWriter') -> None:
- for tag, value in self.properties:
- s = " 9\n$CUSTOMPROPERTYTAG\n 1\n{0}\n 9\n$CUSTOMPROPERTY\n 1\n{1}\n".format(tag, value)
- tagwriter.write_str(s)
- class HeaderSection:
- MIN_HEADER_TAGS = Tags.from_text(MIN_HEADER_TEXT)
- name = 'HEADER'
- def __init__(self, tags: Tags = None):
- tags = tags or self.MIN_HEADER_TAGS
- self.hdrvars = OrderedDict()
- self.custom_vars = CustomVars()
- self._build(iter(tags))
- self._varmap = self._get_varmap()
- def _get_varmap(self) -> dict:
- dxfversion = self.get('$ACADVER', 'AC1009')
- if dxfversion > 'AC1009':
- return dict(VARMAP_R13)
- else:
- return dict(VARMAP_R12)
- def _headervar_factory(self, key: str, value: Any) -> DXFTag:
- if key in self._varmap:
- factory = self._varmap[key]
- return factory(value)
- else:
- raise DXFKeyError('Invalid header variable {}.'.format(key))
- def __len__(self) -> int:
- return len(self.hdrvars)
- def __contains__(self, key) -> bool:
- return key in self.hdrvars
- def _build(self, tags: Iterator[DXFTag]) -> None:
- section_tag = next(tags)
- name_tag = next(tags)
- if section_tag != (0, 'SECTION') or name_tag != (2, 'HEADER'):
- raise DXFStructureError("Critical structure error in HEADER section.")
- groups = group_tags(header_validator(tags), splitcode=9)
- custom_property_stack = [] # collect $CUSTOMPROPERTY/TAG
- for group in groups:
- name = group[0].value
- value = group[1]
- if name in ('$CUSTOMPROPERTYTAG', '$CUSTOMPROPERTY'):
- custom_property_stack.append(value.value)
- else:
- self.hdrvars[name] = HeaderVar(value)
- custom_property_stack.reverse()
- while len(custom_property_stack):
- try:
- self.custom_vars.append(tag=custom_property_stack.pop(), value=custom_property_stack.pop())
- except IndexError: # internal exception
- break
- def varnames(self) -> KeysView:
- return self.hdrvars.keys()
- def write(self, tagwriter: 'TagWriter') -> None:
- def _write(name: str, value: Any) -> None:
- tagwriter.write_tag2(9, name)
- tagwriter.write_str(str(value))
- if self.get('$ACADVER', 'AC1009') == 'AC1009' and self.get('$HANDLING', 1) == 0:
- write_handles = False
- else:
- write_handles = True
- tagwriter.write_str(" 0\nSECTION\n 2\nHEADER\n")
- for name, value in self.hdrvars.items():
- if not write_handles and name == '$HANDSEED':
- continue # skip $HANDSEED
- _write(name, value)
- if name == "$LASTSAVEDBY": # ugly hack, but necessary for AutoCAD
- self.custom_vars.write(tagwriter)
- tagwriter.write_str(" 0\nENDSEC\n")
- def __getitem__(self, key: str) -> Any:
- try:
- return self.hdrvars[key].value
- except KeyError: # map exception
- raise DXFKeyError(str(key))
- def get(self, key: str, default: Any = None) -> Any:
- if key in self.hdrvars:
- return self.__getitem__(key)
- else:
- return default
- def __setitem__(self, key: str, value: Any) -> None:
- try:
- tags = self._headervar_factory(key, value)
- except (IndexError, ValueError):
- raise DXFValueError(str(value))
- self.hdrvars[key] = HeaderVar(tags)
- def __delitem__(self, key: str) -> None:
- try:
- del self.hdrvars[key]
- except KeyError: # map exception
- raise DXFKeyError(str(key))
- class HeaderVar:
- def __init__(self, tag: DXFTag):
- self.tag = tag
- @property
- def code(self) -> int:
- return self.tag[0]
- @property
- def value(self) -> Any:
- return self.tag[1]
- @property
- def ispoint(self) -> bool:
- return self.code == 10
- def __str__(self) -> str:
- if self.ispoint:
- code, value = self.tag
- s = []
- for coord in value:
- s.append(strtag((code, coord)))
- code += 10
- return "".join(s)
- else:
- return strtag(self.tag)
|