DWG 2004 解析系列(三)文件结构之2007

        

目录

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相似。其布局如下:

偏移大小说明
0x007标志串"AC1021\0"
0x0744个0
0x0B1Maintenance release version
0x0C10 or 1 or 3
0x0D4preview address
0x111dwg version
0x121dwg maintance version
0x132codepage index
0x151unknown
0x161app version
0x171app maintance version
0x184security type
0x1c4unknown
0x204summary info address
0x244vba project address
0x284r2007 header address (0x80)
0x2c4application info address
0x300x50unknown

        偏移量为r2007_header_address(0x80)处有0x400字节的数据,其中前0x3D8个字节是经Reed-Solomon (255, 239) 因子为3编码的压缩的r2007header,尾部的0x28个字节是5个64位整数表示的校验数据等。其布局如下:

偏移大小说明
0x008CRC
0x088key
0x108DATA_CRC
0x188DATA_Length
0x20|Data_Length|DATA

            如果DATA_Length为负数,表示DATA未压缩;如果DATA_Length为正数,表示DATA是压缩数据,需要解压。如果需要解压,则解压后的数据长度固定为0x110字节。r2007header的布局如下:

偏移大小说明
0x008header size (通常位0x70)
0x088file size
0x108PageMapCrcCompressed
0x188PageMapCorrectionFactor
0x208PageMapCrcSeed
0x288PageMap2offset(相对于数据页的开始处,在整个文件中偏移应加上文件头的长度0x480)
0x308PageMap2 Id
0x388PageMapOffset(计算方法同PageMap2Offset)
0x408PageMapId
0x488Header2Offset(计算方法同PageMapOffset)
0x508PageMapSizeCompressed
0x588PageMapSizeUncompressed
0x608PageAmount
0x688PageMaxId
0x708Unknown(0x20)
0x788Unknown(0x40)
0x808PageMapCrcUncompressed
0x888Unknown(0xF800)
0x908Unknown(0x4)
0x988Unknown(0x1)
0xA08SectionAmount(=section总数+1)
0xA88SectionMapCrcUncompressed
0xB08SectionMapSizeCompressed
0xB88SectionMap2Id
0xC08SectionMapId
0xC88

SectionMapSizeUncompressed

0xD08SectionMapCrcCompressed
0xD88SectionMapCorrectionFactor
0xE08SectionMapCrcSeed
0xE88StreamVersion(通常为0x60100)
0xF08

CrcSeed

0xF88CrcSeedEncoded
0x1008RandomSeed
0x1088Header 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_comppages_map_size_comp sections_map_size_comp
size_uncomppages_map_size_uncompsections_map_size_uncomp
repeat_countpages_map_correctionsections_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的数据布局如下:

偏移大小说明
0x008page size
0x088page number
0x108page size
0x188page number
......

         对section map的解析要略微复杂一些,其数据布局为:

偏移大小说明
0x008data size
0x088max size
0x108encrption
0x188hashcode
0x208section name length,包含尾0的2个字节
0x288unknown
0x308encoding
0x388number of pages
0x40section name length

UNICODE section name end with "\0\0"

[number of pages]组8page data offset
8page size
8page id
8page uncompressed size
8page compressed size
8page checksum
8page 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继续缠绵。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值