duangsuse::Echo
顺手发点截图 #elec #PL #blog #cs
体验了 EPL(懒得检查表达式了)、Fritzing(这个玩意是用来进行嵌入式设计的,当然你也可以理解为开发板编程什么的,可以画原理图、建面包版和写串口通讯代码)
因为打印了很多博文的缘故,已经开始手动处理网页来尽可能压榨一面 A4 纸的信息量
因为打印了很多博文的缘故,已经开始手动处理网页来尽可能压榨一面 A4 纸的信息量
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...