R 大 09 年就那么大佬了,难怪现在我都看不见他一样了... 这世界有代沟啊
duangsuse::Echo
htmlPrint.zip
Agda 的 coinductive record 么... 我还没学会,emmm。
Agda 环境我还没建立,到时候建立了会发一些简单的证明帮助大家入门。
Agda 环境我还没建立,到时候建立了会发一些简单的证明帮助大家入门。
duangsuse::Echo
立即 公开维护(
AXMLParser parser = new AXMLParser(apkFileInputStream);
int eventType = parser.getType();
while (eventType != AXMLParser.END_DOCUMENT) {
String parserName = parser.getName();
boolean isManifest = "manifest".equals(parserName);
[...]
eventType = parser.next();
}
这个原来的玩意是用流模式的...我也打算这么做,当然也会提供扫描整个文档的辅助方法
这种方式也被 LLVM Cookbook 里的 TOY 语言 Lexer 采用(get_token() 函数从输入流扫描,然后返回词条类型,业务代码判断词条类型访问相应静态变量拿信息)
就作为 Iterable 吧,因为我觉得这种方式(eventType + static field 存储 AXML 结构信息)不够面向对象,反而能嗅出点过程式的端倪。
换句话说,我觉得我应该这样封装:
val parser = AxmlSerializer.Reader(axmlFileInputStream)虽然这样会导致它不够『底层』以至于不是所有 xmlparser 可以处理的文档它都可以处理,但我还是觉得... 不错
for (node in parser.treeIterator) {
when (node is AxmlTag && node.tag == "manifest") {
// [...]
}
}
不过... 其实鱼和熊掌可以兼得,先做一个流处理最底层的 AxmlSequencer,再在上面封装 AxmlSerializer.Reader 不就好了吗?
流处理,最下面是 Binary 数据的 Reader (Extension),提供最底层的二进制格式 DataView
中间一层是文件大格式的 Scanner (Reader),扫描 AXML 『大体』的文件格式(Chunk)
最顶端一层提供 AxmlTree 流接口和帮助函数,每次需要新 node 时就看看自己的缓冲区里有没有剩下的对象可供返回(数据指针移动)
如果没有了,向底层 ask 新的 chunck,拆分,入队,否则返回已经扫描出来的对象
val treeIterator: Iterator<AxmlNode>
get() = asIterator()
fun asIterator(): AxmlNodeIterator<AxmlNode> {
return /* 实现 next 和 hasNext,如果队列为空则从 Sequencer 里读取下一块,拆分,存到 NodeIterator 的队列里,否则返回出队元素 */
}
duangsuse::Echo
AXMLParser parser = new AXMLParser(apkFileInputStream); int eventType = parser.getType(); while (eventType != AXMLParser.END_DOCUMENT) { String parserName = parser.getName(); boolean isManifest = "manifest".equals(parserName); [...] eventType…
https://github.com/duangsuse/AxmlSerializer/wiki/Binary-Serialization-%E7%B1%BB%E8%A6%81%E6%8F%90%E4%BE%9B%E7%9A%84%E6%88%90%E5%91%98%E5%92%8C%E6%96%B9%E6%B3%95%E6%93%8D%E4%BD%9C#binary-serializatoin
我正在准备分析手头上的资料总结出『后面』的文件格式,等我验证规范有效之后,就会开始写一个二进制序列化类库,使用这个线性字节流结构提取式类库解决 AxmlSerializer 的问题
新的库有糖能够使得文件格式的表达更具定义式风格,避免了使用旧式的 byte array 一大堆算偏移量、提取字节数组组装某种数值、裁切子序列的操作(一些不嫌麻烦的库现在依然选择这种方式)
🤔
AAPT2 AXML 文件格式的总结,将在这里讨论
为了方便快速了解格式详情,会使用弱类型的『脚本语言』Ruby 进行 STDIN IO 解析 AXML 文件基础结构。
我正在准备分析手头上的资料总结出『后面』的文件格式,等我验证规范有效之后,就会开始写一个二进制序列化类库,使用这个线性字节流结构提取式类库解决 AxmlSerializer 的问题
新的库有糖能够使得文件格式的表达更具定义式风格,避免了使用旧式的 byte array 一大堆算偏移量、提取字节数组组装某种数值、裁切子序列的操作(一些不嫌麻烦的库现在依然选择这种方式)
@ByteStruct这样对于简单的结构体,在 parser 里面调用
class ResChunkHeader {
@Type(Unsigned16) ChunkType type;
@Type(Unsigned32) long size;
}
reader.readStruct(ResChunkHeader.class) 就可以了🤔
AAPT2 AXML 文件格式的总结,将在这里讨论
为了方便快速了解格式详情,会使用弱类型的『脚本语言』Ruby 进行 STDIN IO 解析 AXML 文件基础结构。
GitHub
Binary Serialization 类要提供的成员和方法操作
Android AAPT2-compatible AXML Binary XML format parser/generator - duangsuse-valid-projects/AxmlSerializer
duangsuse::Echo
简单的思路,虽然写了我很久 🤔...
其实有个大小端的问题... 虽然 AXML 作为一种二进制文件格式并不复杂(没有添加 alignment、不需要搞基流定位)
但是还是要求以小端格式存取,至少好像是 String Pool 必须这样 🤔
emmm... 唉
但是还是要求以小端格式存取,至少好像是 String Pool 必须这样 🤔
emmm... 唉
duangsuse::Echo
AndroidManifest.xml
以下是基于这个文件和 https://gist.github.com/duangsuse/3ae94e339eb188fa4ec8a87b6e105331 分析出来确认有效的文件结构:
当然还有 https://github.com/aosp-mirror/platform_frameworks_base/tree/pie-release/tools/aapt2
AAPT2
https://github.com/aosp-mirror/platform_frameworks_base/blob/pie-release/tools/aapt2/cmd/Dump.cpp#L79
当然还有 https://github.com/aosp-mirror/platform_frameworks_base/tree/pie-release/tools/aapt2
AAPT2
https://github.com/aosp-mirror/platform_frameworks_base/blob/pie-release/tools/aapt2/cmd/Dump.cpp#L79
Gist
手把手教你解析AXML - CSDN https://blog.csdn.net/beyond702/article/details/51830108
手把手教你解析AXML - CSDN https://blog.csdn.net/beyond702/article/details/51830108 - csdn-beyond702-51830108.md
乘着 Telegram 还能够连上赶快
== BinaryDataReader 的必须基础操作,我所希望的
+ skipNBytes(n)
+ readNBytes(n)
+ readU8 / readI8
+ readU16 / readI16
+ readU32 / readI32
+ readU64 / readI64
+ readCStr / readXPrefixStr
+ readNX
+ skipX
+ checkX
和 java 的 DataInputStream 相比,它缺少:
+ readUTF
+ readLine
+ readFully <1 overloads>
+ read Float/Double/Char/Boolean
它实现了 ExtDataInput 扩展类的
+ skipInt(skipX)
+ readIntArray(readNX)
+ skipCheckX(checkX)
+ skipBytes(skipNBytes)(更努力地跳过这些字节,或者说坚持一定要跳过而不因为被打断而终止,定义如下)
因为没有必要(只是处理二进制数据)。
== BinaryDataReader 的必须基础操作,我所希望的
+ skipNBytes(n)
+ readNBytes(n)
+ readU8 / readI8
+ readU16 / readI16
+ readU32 / readI32
+ readU64 / readI64
+ readCStr / readXPrefixStr
+ readNX
+ skipX
+ checkX
和 java 的 DataInputStream 相比,它缺少:
+ readUTF
+ readLine
+ readFully <1 overloads>
+ read Float/Double/Char/Boolean
它实现了 ExtDataInput 扩展类的
+ skipInt(skipX)
+ readIntArray(readNX)
+ skipCheckX(checkX)
+ skipBytes(skipNBytes)(更努力地跳过这些字节,或者说坚持一定要跳过而不因为被打断而终止,定义如下)
proc int skipNBytes(int n) {
int skipped = 0, now;
while skipped < n AND now = super.skipBytes(n - skipped) >0 { total += now; }
return skipped;
}
+ readNullEndedString (readCStr)因为没有必要(只是处理二进制数据)。
duangsuse::Echo
以下是基于这个文件和 https://gist.github.com/duangsuse/3ae94e339eb188fa4ec8a87b6e105331 分析出来确认有效的文件结构: 当然还有 https://github.com/aosp-mirror/platform_frameworks_base/tree/pie-release/tools/aapt2 AAPT2 https://github.com/aosp-mirror/platform_frameworks_base/blob/pie…
首先:AXMLParser 它怎么看 AXML 文件格式:
Axml -> little-endian
int 0x00080003 (其实这种定义是不足够健壮的,它利用了 Top Chunk 的性质,硬编码了 Chunk Type 和 Chunk Header Length)
int chunkSize
StringBlock strb
StringBlock -> little-endian
skipCheckChunkTypeInt(CHUNK_STRINGPOOL_TYPE, CHUNK_NULL_TYPE)
int chunkSize
int stringCount
int styleCount
int flags
int stringsOffset
int stylesOffset
prop isUTF8 = flags & 0x00000100
int[stringCount] stringOffsets
prop stringOwns = [stringCount; -1]
if styleCount != 0 then int[styleCount] styleOffsets
prop size = if styleCount != 0 then stylesOffset else chunkSize end - stringsOffset
byte[size] strings
strings = readFully
if stylesOffset != 0 then
prop size = (chunkSize - stylesOffset)
styles = int[size / 4]
prop remaining = size % 4
if remaining >= 1 then while remaining-- >0 do skipByte
Axml -> little-endian
int 0x00080003 (其实这种定义是不足够健壮的,它利用了 Top Chunk 的性质,硬编码了 Chunk Type 和 Chunk Header Length)
int chunkSize
StringBlock strb
StringBlock -> little-endian
skipCheckChunkTypeInt(CHUNK_STRINGPOOL_TYPE, CHUNK_NULL_TYPE)
int chunkSize
int stringCount
int styleCount
int flags
int stringsOffset
int stylesOffset
prop isUTF8 = flags & 0x00000100
int[stringCount] stringOffsets
prop stringOwns = [stringCount; -1]
if styleCount != 0 then int[styleCount] styleOffsets
prop size = if styleCount != 0 then stylesOffset else chunkSize end - stringsOffset
byte[size] strings
strings = readFully
if stylesOffset != 0 then
prop size = (chunkSize - stylesOffset)
styles = int[size / 4]
prop remaining = size % 4
if remaining >= 1 then while remaining-- >0 do skipByte
This media is not supported in your browser
VIEW IN TELEGRAM
我真的搞不懂为啥要算那么多... 而且为啥这些结构不在开始创建数据对象的时候就计算好,非得存下二进制每次使用的时候再去算... 连这点开销都受不起还是说从 C++ 翻译过来的...
好吧... 其实算和控制结构是必要的,所以我要吐槽的其实是为什么不『完整反序列化』、为什么要将他们单独字节数组存下来重新解析而不是用 stream reader 处理好了...
要知道,一个问题,两种解决方案风格可是很难看的...
写着觉得自己爽了,你看还用了个 ++i 哦、还用到了 block scoping 哦
过几天再读一下就爽了,还不如写简单点... 多用命名和列表处理方法... 🤔
这还没有解析完... 还是子字节数组... emmmm...
好吧... 其实算和控制结构是必要的,所以我要吐槽的其实是为什么不『完整反序列化』、为什么要将他们单独字节数组存下来重新解析而不是用 stream reader 处理好了...
要知道,一个问题,两种解决方案风格可是很难看的...
写着觉得自己爽了,你看还用了个 ++i 哦、还用到了 block scoping 哦
过几天再读一下就爽了,还不如写简单点... 多用命名和列表处理方法... 🤔
这还没有解析完... 还是子字节数组... emmmm...
duangsuse::Echo
🤔 AAPT 和 AAPT2,我觉得 AAPT 就已经足够,因为它已经能够 handle 很多软件包的 Manifest 和 AXML 了,ARSC 文件我下次再说
#Ruby #Project 一个失败的尝试,但是我也了解了二进制 IO 的一些信息
https://github.com/duangsuse/AxmlSerializer/tree/master/RubyAXML
失败是因为我没有时间去完成,但是我也成功设计了个可用的二进制读写器,可惜没有写功能测试。
https://github.com/duangsuse/AxmlSerializer/tree/master/RubyAXML
失败是因为我没有时间去完成,但是我也成功设计了个可用的二进制读写器,可惜没有写功能测试。
GitHub
duangsuse/AxmlSerializer
Android AAPT2-compatible AXML Binary XML format parser/generator - duangsuse/AxmlSerializer
和隔壁的 sdklite 纯 Java aapt 实现对比,情商(显然,二进制每次判计算、算偏移量小哥非常的...呃...秀操作,至于后面那个手动判断选择增加偏移量再索引的 UtfString 长度提取器,更是秀破天际)一目了然
但是 — 你写这么多有什么暖用呢?虽然看起来不明觉厉而且非常显得大佬,但是程序执行的速度也并不比 stream 法快多少 — 甚至可能更慢,因为分配了更多临时的数据子序列拷贝 🤔
况且这个可怜的秀库最后是没有写完烂尾的下场 — 其实很多时候,简单反而好(但不是说,因为简单是好的就不应该去了解学习复杂的东西)。
记得 The Little Schemer 上说,好的程序会反映出它所处理数据的结构
看着两段代码的对比,我觉得真的就是这样... 好的程序反映出它所处理数据的结构,给数据以表述式的灵活,而不是死板板地『间接』『富有计算性』操作存储器,然后把一切复杂度,放到程序员手中。
(基本只是类似的而已,因为很多其实... 呃,一些项目最后没有真正彻底的实现解析算法,所以我找了些差不多的)
😐 AAPT 的 restable.cpp 和 StringPool、Resources 都是有意思的源文件,可是他们都不包含解析器算法,不过我找到了序列化器。
😐 [不佳实践:没有真正按规范解析 AXML(partial,lossy 解析提取出不完整的结构,丢失了不少信息)、不够模块化] https://github.com/shazam/axmlparser/blob/master/src/main/java/com/shazam/axmlparser/AXMLParser.java#L255
😐 [不佳实践:创建了太多份拷贝、依赖静态类变量、手算偏移量、用 byte 数组替代其真正表达的 Int32 信息] https://github.com/duangsuse/AXMLEdit/blob/master/src/main/java/cn/wjdiankong/axmledit/chunk/EndNameSpaceChunk.java
👍 [Good OO Practice] https://github.com/sdklite/aapt/blob/master/src/main/java/com/sdklite/aapt/AssetEditor.java#L627
不错不错~
真理啊。 👊
但是 — 你写这么多有什么暖用呢?虽然看起来不明觉厉而且非常显得大佬,但是程序执行的速度也并不比 stream 法快多少 — 甚至可能更慢,因为分配了更多临时的数据子序列拷贝 🤔
况且这个可怜的秀库最后是没有写完烂尾的下场 — 其实很多时候,简单反而好(但不是说,因为简单是好的就不应该去了解学习复杂的东西)。
记得 The Little Schemer 上说,好的程序会反映出它所处理数据的结构
看着两段代码的对比,我觉得真的就是这样... 好的程序反映出它所处理数据的结构,给数据以表述式的灵活,而不是死板板地『间接』『富有计算性』操作存储器,然后把一切复杂度,放到程序员手中。
(基本只是类似的而已,因为很多其实... 呃,一些项目最后没有真正彻底的实现解析算法,所以我找了些差不多的)
😐 AAPT 的 restable.cpp 和 StringPool、Resources 都是有意思的源文件,可是他们都不包含解析器算法,不过我找到了序列化器。
😐 [不佳实践:没有真正按规范解析 AXML(partial,lossy 解析提取出不完整的结构,丢失了不少信息)、不够模块化] https://github.com/shazam/axmlparser/blob/master/src/main/java/com/shazam/axmlparser/AXMLParser.java#L255
😐 [不佳实践:创建了太多份拷贝、依赖静态类变量、手算偏移量、用 byte 数组替代其真正表达的 Int32 信息] https://github.com/duangsuse/AXMLEdit/blob/master/src/main/java/cn/wjdiankong/axmledit/chunk/EndNameSpaceChunk.java
👍 [Good OO Practice] https://github.com/sdklite/aapt/blob/master/src/main/java/com/sdklite/aapt/AssetEditor.java#L627
不错不错~
真理啊。 👊
GitHub
aosp-mirror/platform_frameworks_base
Contribute to aosp-mirror/platform_frameworks_base development by creating an account on GitHub.