refactor: excel parse

This commit is contained in:
Blizzard
2026-04-16 10:01:11 +08:00
parent 680ecc320f
commit f62f95ec02
7941 changed files with 2899112 additions and 0 deletions
@@ -0,0 +1,5 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
from .loader import load, readfile
from .fileheader import FileHeader
@@ -0,0 +1,82 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
from typing import Iterable, Tuple
import struct
from ezdxf.tools.binarydata import BitStream
from ezdxf.entities import DXFClass
from .const import *
from .crc import crc8
from .fileheader import FileHeader
from .header_section import DwgSectionLoader
def load_classes_section(specs: FileHeader, data: Bytes, crc_check=False):
if specs.version <= ACAD_2000:
return DwgClassesSectionR2000(specs, data, crc_check)
else:
return DwgClassesSectionR2004(specs, data, crc_check)
class DwgClassesSectionR2000(DwgSectionLoader):
def load_data_section(self, data: Bytes) -> Bytes:
if self.specs.version > ACAD_2000:
raise DwgVersionError(self.specs.version)
seeker, section_size = self.specs.sections[CLASSES_ID]
return data[seeker : seeker + section_size]
def load_classes(self) -> Iterable[Tuple[int, DXFClass]]:
sentinel = self.data[:SENTINEL_SIZE]
if (
sentinel
!= b"\x8D\xA1\xC4\xB8\xC4\xA9\xF8\xC5\xC0\xDC\xF4\x5F\xE7\xCF\xB6\x8A"
):
raise DwgCorruptedClassesSection(
"Sentinel for start of CLASSES section not found."
)
start_index = SENTINEL_SIZE
bs = BitStream(
self.data[start_index:],
dxfversion=self.specs.version,
encoding=self.specs.encoding,
)
class_data_size = bs.read_unsigned_long() # data size in bytes
end_sentinel_index = SENTINEL_SIZE + 6 + class_data_size
end_index = end_sentinel_index - 2
end_bit_index = (3 + class_data_size) << 3
while bs.bit_index < end_bit_index:
class_num = bs.read_bit_short()
dxfattribs = {
"flags": bs.read_bit_short(), # version?
"app_name": bs.read_text(),
"cpp_class_name": bs.read_text(),
"name": bs.read_text(),
"was_a_proxy": bs.read_bit(),
"is_an_entity": int(bs.read_bit_short() == 0x1F2),
}
yield class_num, DXFClass.new(dxfattribs=dxfattribs)
if self.crc_check and False:
check = struct.unpack_from("<H", self.data, end_index)[0]
# TODO: classes crc check
# Which data should be checked? This is not correct:
crc = crc8(self.data[start_index:end_index])
if check != crc:
raise CRCError("CRC error in classes section.")
sentinel = self.data[
end_sentinel_index : end_sentinel_index + SENTINEL_SIZE
]
if (
sentinel
!= b"\x72\x5E\x3B\x47\x3B\x56\x07\x3A\x3F\x23\x0B\xA0\x18\x30\x49\x75"
):
raise DwgCorruptedClassesSection(
"Sentinel for end of CLASSES section not found."
)
class DwgClassesSectionR2004(DwgClassesSectionR2000):
def load_data(self, data: Bytes) -> Bytes:
raise NotImplementedError()
@@ -0,0 +1,45 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
from typing import Union
ACAD_13 = "AC1012"
ACAD_14 = "AC1014"
ACAD_2000 = "AC1015"
ACAD_2004 = "AC1018"
ACAD_2007 = "AC1021"
ACAD_2010 = "AC1024"
ACAD_2013 = "AC1027"
ACAD_2018 = "AC1032"
ACAD_LATEST = ACAD_2018
SUPPORTED_VERSIONS = [ACAD_13, ACAD_14, ACAD_2000]
HEADER_ID = 0
CLASSES_ID = 1
OBJECTS_ID = 2
SENTINEL_SIZE = 16
Bytes = Union[bytes, bytearray, memoryview]
class DwgError(Exception):
pass
class DwgVersionError(DwgError):
pass
class DwgCorruptedFileHeader(DwgError):
pass
class DwgCorruptedClassesSection(DwgError):
pass
class DwgCorruptedHeaderSection(DwgError):
pass
class CRCError(DwgError):
pass
@@ -0,0 +1,83 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
__all__ = ["crc8", "crc32"]
from .const import Bytes
def crc8(data: Bytes, seed: int = 0) -> int:
for byte in data:
index = byte ^ (seed & 0xFF)
seed = (seed >> 8) & 0xFF
seed ^= CRC8_TABLE[index & 0xFF]
return seed
def crc32(data: Bytes, seed: int = 0) -> int:
inverted_crc = ~seed
for byte in data:
inverted_crc = (inverted_crc >> 8) ^ CRC32_TABLE[
(inverted_crc ^ byte) & 0xFF
]
return ~inverted_crc
# fmt: off
# Source: Open Design Specification for .dwg
CRC8_TABLE = [
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1,
0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40,
0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1,
0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1,
0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40,
0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1,
0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0,
0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740,
0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0,
0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1,
0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140,
0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0,
0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0,
0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341,
0x4100, 0x81C1, 0x8081, 0x4040,
]
# Source: Open Design Specification for .dwg
CRC32_TABLE = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
]
# fmt: on
@@ -0,0 +1,92 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
from typing import Dict, Tuple
import struct
from .const import *
from .crc import crc8
codepage_to_encoding = {
37: "cp874", # Thai,
38: "cp932", # Japanese
39: "gbk", # UnifiedChinese
40: "cp949", # Korean
41: "cp950", # TradChinese
28: "cp1250", # CentralEurope
29: "cp1251", # Cyrillic
30: "cp1252", # WesternEurope
32: "cp1253", # Greek
33: "cp1254", # Turkish
34: "cp1255", # Hebrew
35: "cp1256", # Arabic
36: "cp1257", # Baltic
}
FILE_HEADER_MAGIC = {
3: 0xA598,
4: 0x8101,
5: 0x3CC4,
6: 0x8461,
}
class FileHeader:
def __init__(self, data: Bytes, crc_check=False):
self.crc_check = crc_check
if len(data) < 6:
raise DwgVersionError("Not a DWG file.")
ver = data[:6].decode(errors="ignore") # type: ignore
if ver not in SUPPORTED_VERSIONS:
raise DwgVersionError(
f"Not a DWG file or unsupported DWG version, signature: {ver}."
)
self.version: str = ver
codepage: int = struct.unpack_from("<h", data, 0x13)[0]
self.encoding = codepage_to_encoding.get(codepage, "cp1252")
self.maintenance_release_version = data[0xB]
self.sections: Dict[int, Tuple[int, int]] = dict()
if self.version <= ACAD_2000:
self.r2000_header(data)
else:
raise DwgVersionError(self.version)
def r2000_header(self, data: Bytes):
index = 0x15
section_count: int = struct.unpack_from("<L", data, index)[0]
index += 4
fmt = "<BLL"
record_size = struct.calcsize(fmt)
for record in range(section_count):
# 0: HEADER_ID
# 1: CLASSES_ID
# 2: OBJECTS_ID
num, seeker, size = struct.unpack_from(fmt, data, index)
index += record_size
self.sections[num] = (seeker, size)
if self.crc_check:
# CRC from first byte of file until start of crc value
check = (
crc8(data[:index], seed=0)
^ FILE_HEADER_MAGIC[len(self.sections)]
)
crc = struct.unpack_from("<H", data, index)[0]
if crc != check:
raise CRCError("CRC error in file header.")
index += 2
sentinel = data[index : index + SENTINEL_SIZE]
if (
sentinel
!= b"\x95\xA0\x4E\x28\x99\x82\x1A\xE5\x5E\x41\xE0\x5F\x9D\x3A\x4D\x00"
):
raise DwgCorruptedFileHeader(
"Corrupted DXF R13/14/2000 file header."
)
def print(self):
print(f"DWG version: {self.version}")
print(f"encoding: {self.encoding}")
print(f"Records: {len(self.sections)}")
print("Header: seeker {0[0]} size: {0[1]}".format(self.sections[0]))
print("Classes: seeker {0[0]} size: {0[1]}".format(self.sections[1]))
print("Objects: seeker {0[0]} size: {0[1]}".format(self.sections[2]))
@@ -0,0 +1,657 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
from typing import Dict, Any, List, Tuple
from abc import abstractmethod
import struct
from ezdxf.lldxf.const import acad_release_to_dxf_version
from ezdxf.tools.binarydata import BitStream
from .const import *
from .crc import crc8
from .fileheader import FileHeader
def load_header_section(specs: FileHeader, data: Bytes, crc_check=False):
if specs.version <= ACAD_2000:
return DwgHeaderSectionR2000(specs, data, crc_check)
else:
return DwgHeaderSectionR2004(specs, data, crc_check)
class DwgSectionLoader:
def __init__(self, specs: FileHeader, data: Bytes, crc_check=False):
self.specs = specs
self.crc_check = crc_check
self.data = self.load_data_section(data)
@abstractmethod
def load_data_section(self, data: Bytes) -> Bytes:
...
class DwgHeaderSectionR2000(DwgSectionLoader):
def load_data_section(self, data: Bytes) -> Bytes:
if self.specs.version > ACAD_2000:
raise DwgVersionError(self.specs.version)
seeker, section_size = self.specs.sections[HEADER_ID]
return data[seeker : seeker + section_size]
def load_header_vars(self) -> Dict:
data = self.data
sentinel = data[:16]
if (
sentinel
!= b"\xCF\x7B\x1F\x23\xFD\xDE\x38\xA9\x5F\x7C\x68\xB8\x4E\x6D\x33\x5F"
):
raise DwgCorruptedHeaderSection(
"Sentinel for start of HEADER section not found."
)
index = 16
size = struct.unpack_from("<L", data, index)[0]
index += 4
bs = BitStream(
data[index : index + size],
dxfversion=self.specs.version,
encoding=self.specs.encoding,
)
hdr_vars = parse_header(bs)
index += size
if self.crc_check:
check = struct.unpack_from("<H", data, index)[0]
# CRC of data from end of sentinel until start of crc value
crc = crc8(data[16:-18], seed=0xC0C1)
if check != crc:
raise CRCError("CRC error in header section.")
sentinel = data[-16:]
if (
sentinel
!= b"\x30\x84\xE0\xDC\x02\x21\xC7\x56\xA0\x83\x97\x47\xB1\x92\xCC\xA0"
):
raise DwgCorruptedHeaderSection(
"Sentinel for end of HEADER section not found."
)
return hdr_vars
class DwgHeaderSectionR2004(DwgHeaderSectionR2000):
def load_data(self, data: Bytes) -> Bytes:
raise NotImplementedError()
CMD_SET_VERSION = "ver"
CMD_SKIP_BITS = "skip_bits"
CMD_SKIP_NEXT_IF = "skip_next_if"
CMD_SET_VAR = "var"
def _min_max_versions(version: str) -> Tuple[str, str]:
min_ver = ACAD_13
max_ver = ACAD_LATEST
if version != "all":
v = version.split("-")
if len(v) > 1:
min_ver = acad_release_to_dxf_version[v[0].strip()]
max_ver = acad_release_to_dxf_version[v[1].strip()]
else:
v_str: str = v[0].strip()
if v_str[-1] == "+":
min_ver = acad_release_to_dxf_version[v_str[:-1]]
else:
min_ver = max_ver = acad_release_to_dxf_version[v_str]
return min_ver, max_ver
def load_commands(desc: str) -> List[Tuple[str, Any]]:
commands = []
lines = desc.split("\n")
for line in lines:
line = line.strip()
if not line or line[0] == "#":
continue
try:
command, param = line.split(":")
except ValueError:
raise ValueError(f"Unpack Error in line: {line}")
command = command.strip()
param = param.split("#")[0].strip()
if command == CMD_SET_VERSION:
commands.append((CMD_SET_VERSION, _min_max_versions(param)))
elif command in {CMD_SKIP_BITS, CMD_SKIP_NEXT_IF}:
commands.append((command, param)) # type: ignore
elif command[0] == "$":
commands.append((CMD_SET_VAR, (command, param)))
else:
raise ValueError(f"Unknown command: {command}")
return commands
def parse_bitstream(
bs: BitStream, commands: List[Tuple[str, Any]]
) -> Dict[str, Any]:
version = bs.dxfversion
min_ver = ACAD_13
max_ver = ACAD_LATEST
hdr_vars: Dict[str, Any] = dict()
skip_next_cmd = False
for cmd, params in commands:
if skip_next_cmd:
skip_next_cmd = False
continue
if cmd == CMD_SET_VERSION:
min_ver, max_ver = params
elif cmd == CMD_SKIP_BITS:
bs.skip(int(params))
elif cmd == CMD_SKIP_NEXT_IF:
skip_next_cmd = eval(params, None, {"header": hdr_vars})
elif cmd == CMD_SET_VAR:
if min_ver <= version <= max_ver:
name, code = params
hdr_vars[name] = bs.read_code(code)
else:
raise ValueError(f"Unknown command: {cmd}")
return hdr_vars
def parse_header(bs: BitStream) -> Dict[str, Any]:
commands = load_commands(HEADER_DESCRIPTION)
return parse_bitstream(bs, commands)
HEADER_DESCRIPTION = """
ver: R2007
$SIZE_IN_BITS: RL # Size in bits
ver: R2013+
$REQUIREDVERSIONS: BLL # default value 0, read only
ver: all
$UNKNOWN: BD # Unknown, default value 412148564080.0
$UNKNOWN: BD # Unknown, default value 1.0
$UNKNOWN: BD # Unknown, default value 1.0
$UNKNOWN: BD # Unknown, default value 1.0
$UNKNOWN: TV # Unknown text string, default ""
$UNKNOWN: TV # Unknown text string, default ""
$UNKNOWN: TV # Unknown text string, default ""
$UNKNOWN: TV # Unknown text string, default ""
$UNKNOWN: BL # Unknown long, default value 24L
$UNKNOWN: BL # Unknown long, default value 0L;
ver: R13-R14
$UNKNOWN: BS # Unknown short, default value 0
ver: R13-R2000
$CURRENT_VIEWPORT_ENTITY_HEADER: H # Handle of the current viewport entity header (hard pointer)
ver: all
$DIMASO: B
$DIMSHO: B
ver: R13-R14
$DIMSAV: B # Undocumented
ver: all
$PLINEGEN: B
$ORTHOMODE: B
$REGENMODE: B
$FILLMODE: B
$QTEXTMODE: B
$PSLTSCALE: B
$LIMCHECK: B
ver: R13-R14
$BLIPMODE: B
ver: R2004+
$UNKNOWN: B # Undocumented
ver: all
$USRTIMER: B # (User timer on/off)
$SKPOLY: B
$ANGDIR: B
$SPLFRAME: B
ver: R13-R14
$ATTREQ: B
$ATTDIA: B
ver: all
$MIRRTEXT: B
$WORLDVIEW: B
ver: R13-R14
$WIREFRAME: B # Undocumented.
ver: all
$TILEMODE: B
$PLIMCHECK: B
$VISRETAIN: B
ver: R13-R14
$DELOBJ: B
ver: all
$DISPSILH: B
$PELLIPSE: B # (not present in DXF)
$PROXYGRAPHICS: BS
ver: R13-R14
$DRAGMODE: BS
ver: all
$TREEDEPTH: BS
$LUNITS: BS
$LUPREC: BS
$AUNITS: BS
$AUPREC: BS
ver: R13-R14
$OSMODE: BS
ver: all
$ATTMODE: BS
ver: R13-R14
$COORDS: BS
ver: all
$PDMODE: BS
ver: R13-R14
$PICKSTYLE: BS
ver: R2004+
$UNKNOWN: BL
$UNKNOWN: BL
$UNKNOWN: BL
ver: all
$USERI1: BS
$USERI2: BS
$USERI3: BS
$USERI4: BS
$USERI5: BS
$SPLINESEGS: BS
$SURFU: BS
$SURFV: BS
$SURFTYPE: BS
$SURFTAB1: BS
$SURFTAB2: BS
$SPLINETYPE: BS
$SHADEDGE: BS
$SHADEDIF: BS
$UNITMODE: BS
$MAXACTVP: BS
$ISOLINES: BS
$CMLJUST: BS
$TEXTQLTY: BS
$LTSCALE: BD
$TEXTSIZE: BD
$TRACEWID: BD
$SKETCHINC: BD
$FILLETRAD: BD
$THICKNESS: BD
$ANGBASE: BD
$PDSIZE: BD
$PLINEWID: BD
$USERR1: BD
$USERR2: BD
$USERR3: BD
$USERR4: BD
$USERR5: BD
$CHAMFERA: BD
$CHAMFERB: BD
$CHAMFERC: BD
$CHAMFERD: BD
$FACETRES: BD
$CMLSCALE: BD
$CELTSCALE: BD
ver: R13-R2004
$MENUNAME: TV
ver: all
$TDCREATE: BL # (Julian day)
$TDCREATE: BL # (Milliseconds into the day)
$TDUPDATE: BL # (Julian day)
$TDUPDATE: BL # (Milliseconds into the day)
ver: R2004+
$UNKNOWN: BL
$UNKNOWN: BL
$UNKNOWN: BL
ver: all
$TDINDWG: BL # (Days)
$TDINDWG: BL # (Milliseconds into the day)
$TDUSRTIMER: BL # (Days)
$TDUSRTIMER: BL # (Milliseconds into the day)
$CECOLOR: CMC
# with an 8-bit length specifier preceding the handle bytes (standard hex handle form) (code 0).
# The HANDSEED is not part of the handle stream, but of the normal data stream (relevant for R21 and later).
$HANDSEED: H # The next handle
$CLAYER: H # (hard pointer)
$TEXTSTYLE: H # (hard pointer)
$CELTYPE: H # (hard pointer)
ver: R2007+
$CMATERIAL: H # (hard pointer)
ver: all
$DIMSTYLE: H # (hard pointer)
$CMLSTYLE: H # (hard pointer)
ver: R2000+
$PSVPSCALE: BD
ver: all
$PINSBASE: 3BD # (PSPACE)
$PEXTMIN: 3BD # (PSPACE)
$PEXTMAX: 3BD # (PSPACE)
$PLIMMIN: 2RD # (PSPACE)
$PLIMMAX: 2RD # (PSPACE)
$PELEVATION: BD # (PSPACE)
$PUCSORG: 3BD # (PSPACE)
$PUCSXDIR: 3BD # (PSPACE)
$PUCSYDIR: 3BD # (PSPACE)
$PUCSNAME: H # (PSPACE) (hard pointer)
ver: R2000+
$PUCSORTHOREF: H # (hard pointer)
$PUCSORTHOVIEW: BS
$PUCSBASE: H # (hard pointer)
$PUCSORGTOP: 3BD
$PUCSORGBOTTOM: 3BD
$PUCSORGLEFT: 3BD
$PUCSORGRIGHT: 3BD
$PUCSORGFRONT: 3BD
$PUCSORGBACK: 3BD
ver: all
$INSBASE: 3BD # (MSPACE)
$EXTMIN: 3BD # (MSPACE)
$EXTMAX: 3BD # (MSPACE)
$LIMMIN: 2RD # (MSPACE)
$LIMMAX: 2RD # (MSPACE)
$ELEVATION: BD # (MSPACE)
$UCSORG: 3BD # (MSPACE)
$UCSXDIR: 3BD # (MSPACE)
$UCSYDIR: 3BD # (MSPACE)
$UCSNAME: H # (MSPACE) (hard pointer)
ver: R2000+
$UCSORTHOREF: H # (hard pointer)
$UCSORTHOVIEW: BS
$UCSBASE: H # (hard pointer)
$UCSORGTOP: 3BD
$UCSORGBOTTOM: 3BD
$UCSORGLEFT: 3BD
$UCSORGRIGHT: 3BD
$UCSORGFRONT: 3BD
$UCSORGBACK: 3BD
$DIMPOST: TV
$DIMAPOST: TV
ver: R13-R14
$DIMTOL: B
$DIMLIM: B
$DIMTIH: B
$DIMTOH: B
$DIMSE1: B
$DIMSE2: B
$DIMALT: B
$DIMTOFL: B
$DIMSAH: B
$DIMTIX: B
$DIMSOXD: B
$DIMALTD: RC
$DIMZIN: RC
$DIMSD1: B
$DIMSD2: B
$DIMTOLJ: RC
$DIMJUST: RC
$DIMFIT: RC
$DIMUPT: B
$DIMTZIN: RC
$DIMALTZ: RC
$DIMALTTZ: RC
$DIMTAD: RC
$DIMUNIT: BS
$DIMAUNIT: BS
$DIMDEC: BS
$DIMTDEC: BS
$DIMALTU: BS
$DIMALTTD: BS
$DIMTXSTY: H # (hard pointer)
ver: all
$DIMSCALE: BD
$DIMASZ: BD
$DIMEXO: BD
$DIMDLI: BD
$DIMEXE: BD
$DIMRND: BD
$DIMDLE: BD
$DIMTP: BD
$DIMTM: BD
ver: R2007+
$DIMFXL: BD
$DIMJOGANG: BD
$DIMTFILL: BS
$DIMTFILLCLR: CMC
ver: R2000+
$DIMTOL: B
$DIMLIM: B
$DIMTIH: B
$DIMTOH: B
$DIMSE1: B
$DIMSE2: B
$DIMTAD: BS
$DIMZIN: BS
$DIMAZIN: BS
ver: R2007+
$DIMARCSYM: BS
ver: all
$DIMTXT: BD
$DIMCEN: BD
$DIMTSZ: BD
$DIMALTF: BD
$DIMLFAC: BD
$DIMTVP: BD
$DIMTFAC: BD
$DIMGAP: BD
ver: R13-R14
$DIMPOST: T
$DIMAPOST: T
$DIMBLK: T
$DIMBLK1: T
$DIMBLK2: T
ver: R2000+
$DIMALTRND: BD
$DIMALT: B
$DIMALTD: BS
$DIMTOFL: B
$DIMSAH: B
$DIMTIX: B
$DIMSOXD: B
ver: all
$DIMCLRD: CMC
$DIMCLRE: CMC
$DIMCLRT: CMC
ver: R2000+
$DIMADEC: BS
$DIMDEC: BS
$DIMTDEC: BS
$DIMALTU: BS
$DIMALTTD: BS
$DIMAUNIT: BS
$DIMFRAC: BS
$DIMLUNIT: BS
$DIMDSEP: BS
$DIMTMOVE: BS
$DIMJUST: BS
$DIMSD1: B
$DIMSD2: B
$DIMTOLJ: BS
$DIMTZIN: BS
$DIMALTZ: BS
$DIMALTTZ: BS
$DIMUPT: B
$DIMATFIT: BS
ver: R2007+
$DIMFXLON: B
ver: R2010+
$DIMTXTDIRECTION: B
$DIMALTMZF: BD
$DIMALTMZS: T
$DIMMZF: BD
$DIMMZS: T
ver: R2000+
$DIMTXSTY: H # (hard pointer)
$DIMLDRBLK: H # (hard pointer)
$DIMBLK: H # (hard pointer)
$DIMBLK1: H # (hard pointer)
$DIMBLK2: H # (hard pointer)
ver: R2007+
$DIMLTYPE: H # (hard pointer)
$DIMLTEX1: H # (hard pointer)
$DIMLTEX2: H # (hard pointer)
ver: R2000+
$DIMLWD: BS
$DIMLWE: BS
ver: all
$BLOCK_CONTROL_OBJECT: H # (hard owner) Block Record Table
$LAYER_CONTROL_OBJECT: H # (hard owner) Layer Table
$STYLE_CONTROL_OBJECT: H # (hard owner) Style Table
$LINETYPE_CONTROL_OBJECT: H # (hard owner) Linetype Table
$VIEW_CONTROL_OBJECT: H # (hard owner) View table
$UCS_CONTROL_OBJECT: H # (hard owner) UCS Table
$VPORT_CONTROL_OBJECT: H # (hard owner) Viewport table
$APPID_CONTROL_OBJECT: H # (hard owner) AppID Table
$DIMSTYLE_CONTROL_OBJECT: H # (hard owner) Dimstyle Table
ver: R13-R2000
$VIEWPORT_ENTITY_HEADER_CONTROL_OBJECT: H # (hard owner)
ver: all
$ACAD_GROUP_DICTIONARY: H # (hard pointer)
$ACAD_MLINESTYLE_DICTIONARY: H # (hard pointer)
$ROOT_DICTIONARY: H # (NAMED OBJECTS) (hard owner)
ver: R2000+
$TSTACKALIGN: BS # default = 1 (not present in DXF)
$TSTACKSIZE: BS # default = 70 (not present in DXF)
$HYPERLINKBASE: TV
$STYLESHEET: TV
$LAYOUTS_DICTIONARY: H # (hard pointer)
$PLOTSETTINGS_DICTIONARY: H # (hard pointer)
$PLOTSTYLES_DICTIONARY: H # (hard pointer)
ver: R2004+
$MATERIALS_DICTIONARY: H # (hard pointer)
$COLORS_DICTIONARY: H # (hard pointer)
ver: R2007+
$VISUALSTYLE_DICTIONARY: H # (hard pointer)
ver: R2013+
$UNKNOWN: H # (hard pointer)
ver: R2000+
$R2000_PLUS_FLAGS: BL
# CELWEIGHT Flags & 0x001F
# ENDCAPS Flags & 0x0060
# JOINSTYLE Flags & 0x0180
# LWDISPLAY !(Flags & 0x0200)
# XEDIT !(Flags & 0x0400)
# EXTNAMES Flags & 0x0800
# PSTYLEMODE Flags & 0x2000
# OLESTARTUP Flags & 0x4000
$INSUNITS: BS
$CEPSNTYPE: BS
skip_next_if: header['$CEPSNTYPE'] != 3
$CPSNID: H # (present only if CEPSNTYPE == 3) (hard pointer)
$FINGERPRINTGUID: TV
$VERSIONGUID: TV
ver: R2004+
$SORTENTS: RC
$INDEXCTL: RC
$HIDETEXT: RC
$XCLIPFRAME: RC # before R2010 the value can be 0 or 1 only.
$DIMASSOC: RC
$HALOGAP: RC
$OBSCUREDCOLOR: BS
$INTERSECTIONCOLOR: BS
$OBSCUREDLTYPE: RC
$INTERSECTIONDISPLAY: RC
$PROJECTNAME: TV
ver: all
$PAPER_SPACE_BLOCK_RECORD: H # (hard pointer)
$MODEL_SPACE_BLOCK_RECORD: H # (hard pointer)
$BYLAYER_LTYPE: H # (hard pointer)
$BYBLOCK_LTYPE: H # (hard pointer)
$CONTINUOUS_LTYPE: H # (hard pointer)
ver: R2007+
$CAMERADISPLAY: B
$UNKNOWN: BL
$UNKNOWN: BL
$UNKNOWN: BD
$STEPSPERSEC: BD
$STEPSIZE: BD
$3DDWFPREC: BD
$LENSLENGTH: BD
$CAMERAHEIGHT: BD
$SOLIDHIST: RC
$SHOWHIST: RC
$PSOLWIDTH: BD
$PSOLHEIGHT: BD
$LOFTANG1: BD
$LOFTANG2: BD
$LOFTMAG1: BD
$LOFTMAG2: BD
$LOFTPARAM: BS
$LOFTNORMALS: RC
$LATITUDE: BD
$LONGITUDE: BD
$NORTHDIRECTION: BD
$TIMEZONE: BL
$LIGHTGLYPHDISPLAY: RC
$TILEMODELIGHTSYNCH: RC
$DWFFRAME: RC
$DGNFRAME: RC
$UNKNOWN: B
$INTERFERECOLOR: CMC
$INTERFEREOBJVS: H # (hard pointer)
$INTERFEREVPVS: H # (hard pointer)
$CSHADOW: RC
$UNKNOWN: BD
ver: R14+
$UNKNOWN: BS # short (type 5/6 only) these do not seem to be required,
$UNKNOWN: BS # short (type 5/6 only) even for type 5.
$UNKNOWN: BS # short (type 5/6 only)
$UNKNOWN: BS # short (type 5/6 only)
"""
@@ -0,0 +1,88 @@
# Copyright (c) 2020-2021, Manfred Moitzi
# License: MIT License
from typing import Dict
from ezdxf.document import Drawing
from ezdxf.tools import codepage
from ezdxf.sections.header import HeaderSection
from ezdxf.sections.classes import ClassesSection
from ezdxf.sections.tables import TablesSection
from ezdxf.sections.blocks import BlocksSection
from ezdxf.sections.entities import EntitySection
from ezdxf.sections.objects import ObjectsSection
from ezdxf.sections.acdsdata import AcDsDataSection
from .const import *
from .fileheader import FileHeader
from .header_section import load_header_section
from .classes_section import load_classes_section
__all__ = ["readfile", "load"]
def readfile(filename: str, crc_check=False) -> "Drawing":
data = open(filename, "rb").read()
return load(data, crc_check)
def load(data: bytes, crc_check=False) -> Drawing:
doc = DwgDocument(data, crc_check=crc_check)
doc.load()
return doc.doc
class DwgDocument:
def __init__(self, data: Bytes, crc_check=False):
self.data = memoryview(data)
self.crc_check = crc_check
self.specs = FileHeader(data, crc_check=crc_check)
self.doc: Drawing = self._setup_doc()
# Store DXF object types by class number:
self.dxf_object_types: Dict[int, str] = dict()
def _setup_doc(self) -> Drawing:
doc = Drawing(dxfversion=self.specs.version)
doc.encoding = self.specs.encoding
doc.header = HeaderSection.new()
# Setup basic header variables not stored in the header section of the DWG file.
doc.header["$ACADVER"] = self.specs.version
doc.header["$ACADMAINTVER"] = self.specs.maintenance_release_version
doc.header["$DWGCODEPAGE"] = codepage.tocodepage(self.specs.encoding)
doc.classes = ClassesSection(doc)
# doc.tables = TablesSection(doc)
# doc.blocks = BlocksSection(doc)
# doc.entities = EntitySection(doc)
# doc.objects = ObjectsSection(doc)
# doc.acdsdata = AcDsDataSection(doc)
return doc
def load(self):
self.load_header()
self.load_classes()
self.load_objects()
self.store_objects()
def load_header(self) -> None:
hdr_section = load_header_section(self.specs, self.data, self.crc_check)
hdr_vars = hdr_section.load_header_vars()
self.set_header_vars(hdr_vars)
def set_header_vars(self, hdr_vars: Dict):
pass
def load_classes(self) -> None:
cls_section = load_classes_section(
self.specs, self.data, self.crc_check
)
for class_num, dxfclass in cls_section.load_classes():
self.doc.classes.register(dxfclass)
self.dxf_object_types[class_num] = dxfclass.dxf.name
def load_objects(self) -> None:
pass
def store_objects(self) -> None:
pass