DWG 2004 格式解析系列(二)文件结构 |
您所在的位置:网站首页 › dwg文件怎么看 › DWG 2004 格式解析系列(二)文件结构 |
目录 0 总体结构 1 文件头 2 数据 2.1 system section a) system section page header b) Section Map page data c) SectionInfo page data 2.2 Data section 0 总体结构从整体上看,一个dwg文件可分为2部分:文件头和数据,数据部分在物理上分页(page)存储的,在逻辑上由一个或多个页组成一个段(section),如图所示: 文件头长度为0x100个字节,布局如下: 地址 长度(byte) 描述 0x00 7 "AC1018\0" 0x07 4 0x00 0x0B 1 主版本号 0x0C 1 0x00或0x01或0x03 0x0D 4 预览图片的地址 0x11 1 Dwg version 0x12 1 Dwg maintance version 0x13 2 Codepage index 0x15 1 0x00 0x16 1 App version 0x17 1 App maintance version 0x18 4 安全标志 0x0001:加密数据(除了AcDb:Preview and AcDb:SummaryInfo) 0x0002:加密属性(用于AcDb:Preview and AcDb:SummaryInfo) 0x0010:sign data 0x0020:add timestamp 0x1C 4 未知 0x20 4 SummaryInfo地址,points to summary info page + page header size(0x20) 0x24 4 VBA工程地址 0x28 4 0x00000080,(似乎是2004header的地址) 0x2C 0x54 全是0x00 0x80 0x6C 加密的数据,称为2004header 0xEC 0x14 填充数据(据说是魔术字节序列的前0x14字节,未做考证) 开始的7个字节是DWG版本标志串,以AC开头,后跟4个数字表述版本。对应关系为: 标注串AutoCAD的发行版本AC1012R13AC1014R14AC10152000 - 2003AC10182004 - 2006AC10212007 - 2009AC10242010 - 2012AC10272013 - 2017AC10322018 - 2020从AutoCAD2000开始,dwg版本号每3年做一次升级,所以AC标志串中的数字并不是连续的。 0x80处的0x6C个字节的加密数据,与下列0x6C个魔术字节逐一做XOR运算,即可解密。 29 23 BE 84 E1 6C D6 AE 52 90 49 F1 F1 BB E9 EB B3 A6 DB 3C 87 0C 3E 99 24 5E 0D 1C 06 B7 47 DE B3 12 4D C8 43 BB 8B A6 1F 03 5A 7D 09 38 25 1F 5D D4 CB FC 96 F5 45 3B 13 0D 89 0A 1C DB AE 32 20 9A 50 EE 40 78 36 FD 12 49 32 F6 9E 7D 49 DC AD 4F 14 F2 44 40 66 D0 6B C4 30 B7 32 3B A1 22 F6 22 91 9D E1 8B 1F DA B0 CA 99 02这0x6C个魔术字节可以用下面的代码得到 unsigned char pc[0x6c]; int randseed = 1; for (int i=0; i>0x10); }经过以上运算解密后的数据布局如下表,称之为ACAD2004HeaderData,这段数据在文件尾部还有一份,即SecondHeaderData。 字地址 长度(byte) 描述 0x00 12 "AcFssFcAJMB\0" 标志串 0x0C 4 0x00 (long) header address 0x10 4 0x6c(long) header size 0x14 4 0x04 (long) 0x18 4 Root tree node gap 0x1C 4 Lowermost left tree node gap 0x20 4 Lowermost right tree node gap 0x24 4 未知(long) 0x28 4 Last section id 0x2C 4 Last section address 0x30 4 0x00 0x34 4 Second header address 0x38 4 0x00 0x3C 4 Gap 总数 0x40 4 Section总数 0x44 4 0x20 (long) 0x48 4 0x80(long) 0x4C 4 0x40(long) 0x50 4 Page Map Id 0x54 4 Page Map Address 该值是以数据部分为起点的偏移,在整个文件中的偏移需要加上文件头的大小(0x100) 0x58 4 0x00 0x5C 4 Section map Id 0x60 4 Section page array size 0x64 4 Gap array size 0x68 4 CRC32 (long) 在这些数据当中,对解析最重要的当属标红的3个数据了。 (5.25,补充一下文件头的解析) 解析2004的文件头比较简单,只需要很少的代码。先定义如下的文件头结构: #pragma pack(push, 1) typedef struct _tagDwg2004Header { // 务必保持成员的顺序! char version[7]; // 0x00: "AC1018\0" char x07_unknown_0[4]; // 0x07: 4zeros char is_maint; // 0x0B char x0c_0_1_3; // 0x0C: 0 or 1 or 3 uint32_t thumbnail_addr; // 0x0D char dwg_version; // 0x11 char dwg_maint_version; // 0x12 short codepage; // 0x13 char x15_unknown_0; // 0x15 char app_version; // 0x16 char app_maint_version; // 0x17 uint32_t security_type; // 0x18 uint32_t x1c_unknown_0; // 0x1C uint32_t summary_info_address; // 0x20 uint32_t vba_proj_address; // 0x24 uint32_t r2004_header_address; // 0x28: 0x80 char x2c_0[0x54]; // 0x2C: 0 union { char encrypted_data[0x6c]; // 0x80 struct _r2004 { char file_id_string[12]; // "AcFssFcAJMB\0" uint32_t header_address; // 0x00 uint32_t header_size; // 0x6c uint32_t x14_unknown_0; // 0 uint32_t root_tree_node_gap; uint32_t lowermost_left_tree_node_gap; uint32_t lowermost_right_tree_node_gap; uint32_t x24_uknown; uint32_t last_section_id; uint64_t last_page_address; uint64_t second_header_address; uint32_t gap_amount; uint32_t page_amount; uint32_t x44_x20; uint32_t x48_x80; uint32_t x4c_x40; uint32_t page_map_id; uint64_t page_map_address; // offset from DATA, not include this HEADER size uint32_t section_map_id; uint32_t section_array_size; uint32_t gap_array_size; uint32_t crc32; } r2004; }; char padding[0x14]; } Dwg2004Header; // total 0x100 bytes #pragma pack(pop)解析的代码: { // 说明:m_header的类型是上面定义的Dwg2004Header,DWG_DATA是dwg文件的原始数据 memcpy(&m_header, DWG_DATA, sizeof(Dwg2004Header)); // decrypt r2004 header int rseed = 1; for (int i = 0; i < 0x6c; i++) { rseed *= 0x343fd; rseed += 0x269ec3; m_header.encrypted_data[i] ^= (rseed >> 0x10); } } 2 数据dwg的数据是分段(section)组织的,文件中涉及到的数据段有: /// \enum Section type of R2004+ typedef enum _tagDwg2004SectionType { SECTION_UNKNOWN = 0, ///< The very first 160 byte SECTION_HEADER = 1, ///< AcDb:Header SECTION_AUXHEADER = 2, ///< AcDb:AuxHeader SECTION_CLASSES = 3, ///< AcDb:Classes SECTION_HANDLES = 4, ///< AcDb:Handles SECTION_TEMPLATE = 5, ///< AcDb:Template SECTION_OBJFREESPACE = 6, ///< AcDb:ObjFreeSpace SECTION_OBJECTS = 7, ///< AcDb:AcDbObjects SECTION_REVHISTORY = 8, ///< AcDb:RevHistory SECTION_SUMMARYINFO = 9, ///< AcDb:SummaryInfo SECTION_PREVIEW = 10, ///< AcDb:Preview SECTION_APPINFO = 11, ///< AcDb:AppInfo SECTION_APPINFOHISTORY = 12, ///< AcDb:AppInfoHistory SECTION_FILEDEPLIST = 13, ///< AcDb:FileDepList SECTION_SECURITY, ///< AcDb:Security, if stored with a password SECTION_VBAPROJECT, ///< AcDb:VBAProject SECTION_SIGNATURE, ///< AcDb:Signature SECTION_ACDS, ///< AcDb:AcDsPrototype_1b = 12 (ACIS datastorage) SECTION_SECTIONMAP, ///< system section: section map SECTION_PAGEMAP, ///< system section: page map } Dwg2004SectionType;所有的section中,page map段和section map段,这2个section至关重要,必须先根据ACAD2004HeaderData中标红的三个参数从文件中读取,再根据读到的结果,一一读取不同的数据段予以解析。 首先从page map address处读取pagen map,然后从此map中取得section map Id对应的段(即section map section)的地址,并从文件中读出它的数据。这两种section统称为system section,其他的section则称为data section。之后,由这两兄弟配合就可以通过section name确定各种section的数据页在文件中的位置,根据描述信息予以读取。 system section都只有一页,而data section 至少有一页。 2.1 system sectionsystem section的数据是按页(page)组织的。一个page包含2部分,页头和页数据: 项目 长度 header 0x14bytes data 压缩数据,长度由header.CompDataSize指定 其中header对于两种system section来说,结构是一样的,差别在于data的结构的不同。 a) system section page headerHeader的结构: 地址(偏移) 长度(byte) 含义 0x00 4 Page 类型,有2种system page: page map page: 0x41630e3b section map page: 0x4163003b 0x04 4 解压后的数据长度 (DecompDataSize) 0x08 4 压缩后的数据长度 (CompDataSize) 0x0C 4 压缩类型(0x02) 0x10 4 CRC 当 page.CompDataSize==0时,这个system section就结束了,后面也不会再跟随page data。如下图所示就是system section的组织形式: page map段的页数据经解压缩后,为多个(page number, page size)数据对,其中的page number从1开始计数,该数据对记录的是文件中的各数据页的编号和大小。 地址 长度 描述 0x00 4 page number, 1-based 0x04 4 page size 这种数据对一直重复,直到本页的数据耗尽。在读取时,可以顺便计算出各section在文件中的绝对偏移地址:第一个读到的section的地址总是从文件头后(即0x100处)开始,后续读到的section的偏移可从其前一个section的偏移和大小计算得到。 c) Section Mappage data从上面的pagemap只能得到已知某个编号的page的位置和大小,无法得到该page的具体信息,包括压缩否,加密否等等,这时就该section map上场了。section map的page.data解压缩后的布局如下,这是一个复合结构: 偏移 长度 含义 0x00 4 Number of descriptions(num_descs) 0x04 4 Compressed?(1=no, 2=yes, normally 2) 0x08 4 Max_size(normally 0x7400) 0x0C 4 Excrypted?(0=no, 1=yes, 2=unknown) 0x10 4 Num descriptions 2 共有num_descs组 0x00 8 Size of section 0x08 4 Number of pages(num_pages) 0x0C 4 Max decompress size 0x10 4 未知(会不会是long型的Max decompress size的高位?) 0x14 4 Compressed?(1=no,2=yes,normally 2) 0x18 4 Section type 0x1C 4 Encrypted?(0=no,1=yes,2=unknow) 0x20 64 Section name ("AcDbObjects"等等) 共有 num_pages组 0x00 4 page number 0x04 4 page data size 0x08 8 Start offset 对system section的归纳图示: 下面是一个解析实例中,关于AcDbObjects的section map的描述。 Description No.7 ------------------ size: 0x2b0e9 num_pages: 0x6 max_decomp_size: 0x7400 unknown2: 0x1 compressed: 0x2 type: 0x7 encrypted: 0x0 name: AcDb:AcDbObjects No.1 ............. page number: 6 data size: 0x30ea offset: 0x0 unknown: 0x0 No.2 ............. page number: 7 data size: 0x7f0 offset: 0x7400 No.3 ............. number: 8 data size: 0x628 offset: 0xe800 No.4 ............. page number: 9 data size: 0xf1f offset: 0x15c00 No.5 ............. page number: 10 data size: 0xcc0 offset: 0x1d000 No.6 ............. page number: 11 data size: 0xe0c offset: 0x24400 2.2 Data section pagedata section page的布局为: 项目 长度 含义 Header 0x20 加密头 Data DataSize 数据 Padding page size - DataSzie -0x20 填充 对加密头解密后的数据结构为: 偏移 长度 含义 0x00 4 Tag of data section (0x4163043B) 0x04 4 Section type 0x08 4 DataSize, Data的长度 0x0C 4 page size 本page的总长度(包括header,data和padding) 0x10 8 offset,Data解压后在解压缓冲中的存放偏移 0x18 4 Check sum 1 0x1C 4 Check sum 2 加密头的解密方法: 假设0x20长度的头数据存放在header[8]中,offset是本page在dwg文件中的绝对偏移,可从page map中得到。 int32_t header[8]; int32_t mask = 0x4164536b ^ offset; for (int i=0; i |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |