<?php
namespace ApkParser;
use ApkParser\Exceptions\XmlParserException;
class XmlParser
{
const END_DOC_TAG = 0x101;
const START_TAG = 0x102;
const END_TAG = 0x103;
const TEXT_TAG = 0x104;
const RES_STRING_POOL_TYPE = 0x1;
const RES_XML_START_ELEMENT_TYPE = 0x102;
const RES_XML_RESOURCE_MAP_TYPE = 0x180;
private $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
private $bytes = array();
private $ready = false;
public static $indent_spaces = "";
private $xmlObject = NULL;
public function __construct(Stream $apkStream)
{
$this->bytes = $apkStream->getByteArray();
}
public static function decompressFile($file, $destination = NULL)
{
if (!is_file($file)) {
throw new \Exception("{$file} is not a regular file");
}
$parser = new self(new Stream(fopen($file, 'rd')));
file_put_contents($destination === NULL ? $file : $destination, $parser->getXmlString());
}
public function decompress()
{
$headerSize = $this->littleEndianShort($this->bytes, 1 * 2);
$dataSize = $this->littleEndianWord($this->bytes, 2 * 2);
$off = $headerSize;
$resIdsOffset = -1;
$resIdsCount = 0;
while ($off < $dataSize - 8) {
$chunkType = $this->littleEndianShort($this->bytes, $off + 0 * 2);
$chunkHeaderSize = $this->littleEndianShort($this->bytes, $off + 1 * 2);
$chunkSize = $this->littleEndianWord($this->bytes, $off + 2 * 2);
if ($off + $chunkSize > $dataSize) {
break;
}
if ($chunkType == self::RES_STRING_POOL_TYPE) {
$numbStrings = $this->littleEndianWord($this->bytes, $off + 8);
$sitOff = $off + $chunkHeaderSize;
$stOff = $sitOff + $numbStrings * 4;
} else {
if ($chunkType == self::RES_XML_RESOURCE_MAP_TYPE) {
$resIdsOffset = $off + $chunkHeaderSize;
$resIdsCount = ($chunkSize - $chunkHeaderSize) / 4;
} else {
if ($chunkType == self::RES_XML_START_ELEMENT_TYPE) {
break;
}
}
}
$off += $chunkSize;
}
$indentCount = 0;
$startTagLineNo = -2;
while ($off < count($this->bytes)) {
$currentTag = $this->littleEndianShort($this->bytes, $off);
$lineNo = $this->littleEndianWord($this->bytes, $off + 2 * 4);
$nameNsSi = $this->littleEndianWord($this->bytes, $off + 4 * 4);
$nameSi = $this->littleEndianWord($this->bytes, $off + 5 * 4);
switch ($currentTag) {
case self::START_TAG:
$tagSix = $this->littleEndianWord($this->bytes, $off + 6 * 4);
$numbAttrs = $this->littleEndianWord($this->bytes, $off + 7 * 4);
$off += 9 * 4;
$tagName = $this->compXmlString($this->bytes, $sitOff, $stOff, $nameSi);
$startTagLineNo = $lineNo;
$attr_string = "";
for ($ii = 0; $ii < $numbAttrs; $ii++) {
$attrNameNsSi = $this->littleEndianWord($this->bytes, $off);
$attrNameSi = $this->littleEndianWord($this->bytes, $off + 1 * 4);
$attrValueSi = $this->littleEndianWord($this->bytes, $off + 2 * 4);
$attrFlags = $this->littleEndianWord($this->bytes, $off + 3 * 4);
$attrResId = $this->littleEndianWord($this->bytes, $off + 4 * 4);
$off += 5 * 4;
$attrName = $this->compXmlString($this->bytes, $sitOff, $stOff, $attrNameSi);
$attrNameResID = $this->littleEndianWord($this->bytes, $resIdsOffset + $attrNameSi * 4);
if (empty($attrName)) {
$attrName = $this->getResourceNameFromID($attrNameResID);
}
if ($attrValueSi != 0xffffffff && $attrValueSi != -1) {
$attrValue = $this->compXmlString($this->bytes, $sitOff, $stOff, $attrValueSi);
} else {
$attrValue = "0x" . dechex($attrResId);
}
$attr_string .= " " . $attrName . "=\"" . $attrValue . "\"";
}
$this->appendXmlIndent($indentCount, "<" . $tagName . $attr_string . ">");
$indentCount++;
break;
case self::END_TAG:
$indentCount--;
$off += 6 * 4;
$tagName = $this->compXmlString($this->bytes, $sitOff, $stOff, $nameSi);
$this->appendXmlIndent($indentCount, "</" . $tagName . ">");
break;
case self::END_DOC_TAG:
$this->ready = true;
break 2;
break;
case self::TEXT_TAG:
$sentinal = -1;
while ($off < count($this->bytes)) {
$curr = $this->littleEndianWord($this->bytes, $off);
$off += 4;
if ($off > count($this->bytes)) {
throw new \Exception("Sentinal not found before end of file");
}
if ($curr == $sentinal && $sentinal == -1) {
$sentinal = 0;
} else {
if ($curr == $sentinal) {
break;
}
}
}
break;
default:
throw new \Exception("Unrecognized tag code '" . dechex($currentTag) . "' at offset " . $off);
break;
}
}
}
public function compXmlString($xml, $sitOff, $stOff, $str_index)
{
if ($str_index < 0) {
return null;
}
$strOff = $stOff + $this->littleEndianWord($xml, $sitOff + $str_index * 4);
return $this->compXmlStringAt($xml, $strOff);
}
public function appendXmlIndent($indent, $str)
{
$this->appendXml(substr(self::$indent_spaces, 0, min($indent * 2, strlen(self::$indent_spaces))) . $str);
}
public function appendXml($str)
{
$this->xml .= $str . "\r\n";
}
public function compXmlStringAt($arr, $string_offset)
{
$strlen = $arr[$string_offset + 1] << 8 & 0xff00 | $arr[$string_offset] & 0xff;
$string_offset += 2;
$string = "";
$strEnd = $string_offset + $strlen * 2;
if (function_exists("mb_convert_encoding")) {
for ($i = $string_offset; $i < $strEnd; $i++) {
$string .= chr($arr[$i]);
}
$string = mb_convert_encoding($string, "UTF-8", "UTF-16LE");
} else {
for ($i = $string_offset; $i < $strEnd; $i += 2) {
$string .= chr($arr[$i]);
}
}
return $string;
}
public function littleEndianWord($arr, $off)
{
$signShifAmount = PHP_INT_SIZE - 4 << 3;
return ($arr[$off + 3] << 24 & 0xff000000 | $arr[$off + 2] << 16 & 0xff0000 | $arr[$off + 1] << 8 & 0xff00 | $arr[$off] & 0xff) << $signShifAmount >> $signShifAmount;
}
public function littleEndianShort($arr, $off)
{
$signShifAmount = PHP_INT_SIZE - 2 << 3;
return ($arr[$off + 1] << 8 & 0xff00 | $arr[$off] & 0xff) << $signShifAmount >> $signShifAmount;
}
public function output()
{
阿尔法星球
- 粉丝: 1569
- 资源: 250
最新资源
- opc da 转opc ua 、opc 隧道软件 注意:这是两个软件,安装在同一个机器上,可以实现opc da转 opc ua 安装在两个计算机上就可以实现opc tunnel功能,不需要配置d
- java Springboot网上音乐商城(源码+sql+论文)-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 档案管理系统_g2p7x--论文-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- ffmpeg and EasyDarwin
- elk-demo 代码例子,123 45678
- 大学生创新创业训练项目管理系统设计与实现-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 大健康养老公寓管理系统_to14d-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 大学新生报到系统的设计与实现-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 基于Hadoop的高校固定资产管理系统研究与实现_hot14-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 基于Java的大学生迎新系统-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- JavaSpringboot+vue图书购物商城管理系统(源码+sql+论文)-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.rar
- JavaSpringboot学生教务管理系统(源码+sql+文档)-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 个性化电影推荐系统-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- 儿童性教育网站-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip
- JavaSpringboot+vur前后端分离党员信息管理系统(源码+sql+论文)-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.rar
- 430大神asp.net基于三层商品进销存管理系统毕业课程源码设计
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈