sqlite中大量使用了变长整形,为了分析sqlite的数据文件格式 ,这是一个绕不过去的点。变长整数由1至9个字节组成,如果整形值比较小,占用的字节数就少,整形值比较大,占用的字节数就多。这实际上是一种压缩编码技术。
变长整型的每个字节的低7位有效,第8位是标志位。在组成可变长整数的各字节中,前面字节(整数的高位字节)的第8位置1,只有最后一个字节的第8位置0,表示整数结束。觉没觉得得和c语言的字符串存储有异曲同工之妙。字符串的最后一个字节为0表示字符串的结束。而这里字节数组的最高位为0表示变长整数结束。
为了接下来分析中用php处理变长整型,特地实现了几个与变长整型相关的功能函数,主要用于变长整型的编码与解码,以及判断是否为变长整形的最后一个字节。代码很简单,有疑问的朋友直接看代码吧。
变长整型函数代码如下
<?php
//对sqlite的变长整型进行编码与解码的操作
//将sqlite变长整形解码为正常整形值,目前只处理了正数,未考虑负数
function sqliteIntDecode($varInt){
$size = strlen($varInt);
$result = 0;
for($i=0;$i<$size;$i++){
$byteInt = unpack('Cs',substr($varInt,$i,1))['s'];
//echo 'byteInt=',$byteInt,"\n";
//将字节的最高位置为0
$remInt = $byteInt & 0x7f;
//echo 'remInt=',$remInt,"\n";
$result +=$remInt;
//如果不是最后一个字节,则左移7位,相当于乘以128
if($i<$size-1){
$result*=128;
}
}
return $result;
}
//将正常整形值编码为sqlite变长整形,目前只处理了正数,未考虑负数
function sqliteIntEncode($int=0){
if($int==0){
return "\x0";
}
$result ='';
$p=$int;
$count = 0;
while($p > 0 and $count<9){
$r = $p % 128;
//echo 'r=',$r,"\n";
if($count>0){ //在字节的最高位置1
$r = $r | 0x80;
}
$byte = pack('C',$r);
$result = $byte.$result;
$p = floor($p/128);
$count++;
}
return $result;
}
//判断给定的字节是否为变长整形的最后一个字节
function sqliteIntIsLastByte($rawByte){
$byteInt = unpack('Cs',$rawByte)['s'];
$flag = $byteInt & 0x80;
return $flag<=0;
}
//用16进制的形式显示变长整数
function sqliteIntPrint($varInt){
$size = strlen($varInt);
echo "0x";
for($i=0;$i<$size;$i++){
echo unpack('H2s',substr($varInt, $i,1))['s'];
}
echo "\n";
}