简单说,AcDb:Handles section描述的是对象句柄与其存储位置的对应关系,称为ObjectMap,其结构简单易于理解。其中的存储位置,指的是该对象在AcDb:Objects section在解码解压后的数据中的绝对地址。
首先要明确的是,其数据是分页存储的。每页以一个BigEndian short值表示页尺寸(page data + crc的尺寸),当页尺寸值为2(即只包含一个CRC)时,则结束。
贴代码比文字描述要轻松,其实也没什么需要再描述的了。
void CObjectMap::decode(CDataSection::Result data)
{
if (data.buffer == 0 || data.size == 0) return;
CBitChain chain(data.buffer, data.size, UNKNOWN);
uint16_t page_size = 0;
m_obj_map.clear();
do
{
uint32_t page_start = chain.byte();
// page_size: raw short saved as BigEndian
unsigned char sgdc[2];
sgdc[0] = chain.bit_read_RC();
sgdc[1] = chain.bit_read_RC();
page_size = (sgdc[0] << 8) | sgdc[1];
// ODA的描述中是把omd的初始化放在do循环的前面,这是个bug,应该对每页数据初始化
// 也就是说,每页开始的那个handle和offset是初值,后续的应累加计算
ObjMapData omd = { 0, 0 };
while (chain.byte() - page_start < page_size)
{
// the offset from the previous handle. default: 1, unsigned
uint32_t hdl_offset = chain.bit_read_UMC();
// the offset from the previous address. default: object size, signed
int32_t loc_offset = chain.bit_read_MC();
omd.handle += hdl_offset;
omd.offset += loc_offset;
m_obj_map.push_back(omd);
}
// move cursor to CRC
chain.set_byte(page_start + page_size);
chain.set_bit(0);
// ODA:这个CRC是BE short。反正现在没用到它,就这么读过吧
uint16_t crc = chain.bit_read_RS();
} while (page_size > 2);
}
附一个实例: