admin管理员组文章数量:1574121
目录
0 总体结构
1 文件头
2 System section
3 Data section
前文讲述了2004的文件结构,在引言中曾提及2004后的dwg文件结构,除了2007外,基本相同,本文就详细讲述一下2007的文件结构。其实,从2000版后,除了文件结构的不同外(可分为2000,2004,2007三种不同结构),从文件中解析出某个SECTION的数据后,其内部编码都是相同的(即位码,计划后面再详述)。
0 总体结构
总体结构依然是文件头+数据页的组织形式,主要差别在于2007的文件头的不同。
1 文件头
对文件头的解码过程如下图,其中的r2007header类似于2004中的r2004header,但是r2004header只需要在位解密就行。
首先从dwg文件头部读取0x80字节的数据,这部分数据称为MetaData,描述的内容与2004相似。其布局如下:
偏移 | 大小 | 说明 |
0x00 | 7 | 标志串"AC1021\0" |
0x07 | 4 | 4个0 |
0x0B | 1 | Maintenance release version |
0x0C | 1 | 0 or 1 or 3 |
0x0D | 4 | preview address |
0x11 | 1 | dwg version |
0x12 | 1 | dwg maintance version |
0x13 | 2 | codepage index |
0x15 | 1 | unknown |
0x16 | 1 | app version |
0x17 | 1 | app maintance version |
0x18 | 4 | security type |
0x1c | 4 | unknown |
0x20 | 4 | summary info address |
0x24 | 4 | vba project address |
0x28 | 4 | r2007 header address (0x80) |
0x2c | 4 | application info address |
0x30 | 0x50 | unknown |
偏移量为r2007_header_address(0x80)处有0x400字节的数据,其中前0x3D8个字节是经Reed-Solomon (255, 239) 因子为3编码的压缩的r2007header,尾部的0x28个字节是5个64位整数表示的校验数据等。其布局如下:
偏移 | 大小 | 说明 |
0x00 | 8 | CRC |
0x08 | 8 | key |
0x10 | 8 | DATA_CRC |
0x18 | 8 | DATA_Length |
0x20 | |Data_Length| | DATA |
如果DATA_Length为负数,表示DATA未压缩;如果DATA_Length为正数,表示DATA是压缩数据,需要解压。如果需要解压,则解压后的数据长度固定为0x110字节。r2007header的布局如下:
偏移 | 大小 | 说明 |
0x00 | 8 | header size (通常位0x70) |
0x08 | 8 | file size |
0x10 | 8 | PageMapCrcCompressed |
0x18 | 8 | PageMapCorrectionFactor |
0x20 | 8 | PageMapCrcSeed |
0x28 | 8 | PageMap2offset(相对于数据页的开始处,在整个文件中偏移应加上文件头的长度0x480) |
0x30 | 8 | PageMap2 Id |
0x38 | 8 | PageMapOffset(计算方法同PageMap2Offset) |
0x40 | 8 | PageMapId |
0x48 | 8 | Header2Offset(计算方法同PageMapOffset) |
0x50 | 8 | PageMapSizeCompressed |
0x58 | 8 | PageMapSizeUncompressed |
0x60 | 8 | PageAmount |
0x68 | 8 | PageMaxId |
0x70 | 8 | Unknown(0x20) |
0x78 | 8 | Unknown(0x40) |
0x80 | 8 | PageMapCrcUncompressed |
0x88 | 8 | Unknown(0xF800) |
0x90 | 8 | Unknown(0x4) |
0x98 | 8 | Unknown(0x1) |
0xA0 | 8 | SectionAmount(=section总数+1) |
0xA8 | 8 | SectionMapCrcUncompressed |
0xB0 | 8 | SectionMapSizeCompressed |
0xB8 | 8 | SectionMap2Id |
0xC0 | 8 | SectionMapId |
0xC8 | 8 | SectionMapSizeUncompressed |
0xD0 | 8 | SectionMapCrcCompressed |
0xD8 | 8 | SectionMapCorrectionFactor |
0xE0 | 8 | SectionMapCrcSeed |
0xE8 | 8 | StreamVersion(通常为0x60100) |
0xF0 | 8 | CrcSeed |
0xF8 | 8 | CrcSeedEncoded |
0x100 | 8 | RandomSeed |
0x108 | 8 | Header CRC64 |
从以上表格可以看出其与2004header的不同,增加了很多数据项,而且全部向64位转变。
2 System section
接下来,自然是到了解析system section的时间。
首先是Pagemap,我们根据r2007header中参数的指引,从数据流中读取。以下是解析实例中的参数:
pages_map_offset: 0
pages_map_correction: 7
pages_map_size_comp: 84
pages_map_size_uncomp: 170
sections_map_id: 16
sections_map_correction: 4
sections_map_size_comp: 3c9
sections_map_size_uncomp: 8d2
system section只有一个数据页,对page map和section map的读取方式(解码解压)是一样的,直接上代码来解释吧。
方法read_system_page的参数:
参数 | 读page map的page时 | 读section map的page时 |
data | 由pages_map_offset计算 | 从pagemap中查询sections_map_id对应的page的偏移计算得到 |
size_comp | pages_map_size_comp | sections_map_size_comp |
size_uncomp | pages_map_size_uncomp | sections_map_size_uncomp |
repeat_count | pages_map_correction | sections_map_correction |
uint8_t* CSystemSection2007::read_system_page(const uint8_t* data, int64_t size_comp, int64_t size_uncomp, int64_t repeat_count)
{
// pesize: Pre rs Encoded size
// Round to a multiple of 8
uint64_t pesize = ((size_comp + 7) & ~7) * repeat_count;
// Divide pre encoded size by RS k-value (239)
uint64_t block_count = (pesize + 238) / 239;
if (block_count == 0)
{
PRINT("Empty r2007 system page block_count. size_comp: %lld, repeat_count: %lld",
size_comp, repeat_count);
return NULL;
}
// Multiply with codeword size (255) and round to a multiple of 8
uint64_t page_size = (block_count * 255 + 7) & ~7;
uint64_t pedata_size = block_count * 239;
uint8_t* pedata = new uint8_t[pedata_size];
reed_solomon_decode(pedata, data, block_count, 239, page_size);
// allocate memory for decompressing
check_buffer(size_uncomp);
if (size_comp < size_uncomp)
{
CCompressedData2007 comp(pedata, size_comp, size_uncomp);
comp.decompress(m_decomp_data);
}
else
memcpy(m_decomp_data, pedata, size_uncomp);
delete[] pedata;
return m_decomp_data;
}
从代码可知,2007的数据页是需要先RS解码,再解压缩的。
与2004相同的是,这里的page map仍然是(page number,page size)数据对,不同的是,不再分页了,读取顺序是(page size,page number),page map的数据布局如下:
偏移 | 大小 | 说明 |
0x00 | 8 | page size |
0x08 | 8 | page number |
0x10 | 8 | page size |
0x18 | 8 | page number |
...... |
对section map的解析要略微复杂一些,其数据布局为:
偏移 | 大小 | 说明 |
0x00 | 8 | data size |
0x08 | 8 | max size |
0x10 | 8 | encrption |
0x18 | 8 | hashcode |
0x20 | 8 | section name length,包含尾0的2个字节 |
0x28 | 8 | unknown |
0x30 | 8 | encoding |
0x38 | 8 | number of pages |
0x40 | section name length | UNICODE section name end with "\0\0" |
[number of pages]组 | 8 | page data offset |
8 | page size | |
8 | page id | |
8 | page uncompressed size | |
8 | page compressed size | |
8 | page checksum | |
8 | page CRC |
解析实例:
3 Data section
从section map可知,一个data section可能会有多个页,因此同2004一样,按照section map的指引把这些数据页读入,类似于system section page的读取,依然要解码再解压(也可能无压缩),上代码看吧。
uint8_t* CDataSection2007::read_data_page(const uint8_t* data, uint8_t* dest, int64_t page_size,
int64_t size_comp, int64_t size_uncomp)
{
int64_t pesize = ((size_comp + 7) & ~7);
int64_t block_count = (pesize + 250) / 251;
int64_t pedata_size = block_count * 251; //0xFB
uint8_t* pedata = new uint8_t[pedata_size];
reed_solomon_decode(pedata, data, block_count, 251, page_size);
if (size_comp < size_uncomp)
{
CCompressedData2007 comp(pedata, size_comp, size_uncomp);
comp.decompress(dest);
}
else
memcpy(dest, pedata, size_uncomp);
delete[] pedata;
return dest;
}
嗯,2007的结构性解析到这里就算结束了。除了RS编码和解压算法不同外,与2004的结构基本类似。不知道什么原因,此格式只存活了这一届,之后Autodesk就回去找旧爱2004继续缠绵。
版权声明:本文标题:DWG 2004 解析系列(三)文件结构之2007 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1727766057a1128487.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论