# raw.pack 库模块帮助文档

<details>  <summary>使用必读</summary>  <p>

**介绍：**

ardio 的 raw.pack 是 Python 的 struct 库的兼容实现。
使用的二进制格式化语法与 Python 相同（ [请参考 Python struct 模块文档](https://docs.python.org/zh-cn/3.8/library/struct.html) ）。

**工具：**

使用「aardio 工具 » 转换工具 » 原生类型转换」
可以将 Python 二进制格式化串自动转换为结构体声明，并生成用结构体打包解包的示例。
使用结构体打包解包仅需要用到内置函数 raw.convert 与 raw.buffer,
不需要引入 raw.pack 库。

aardio 使用结构体处理二进制更为简单，速度也更快，结构体描述二进制数据的可读性也更好。
但是对于大端序格式串使用 raw.pack 会省事一些，这是因为  raw.pack 与 raw.pack.unpack 会自动转换大端序。
但结构体使用的是小端序，大端序要使用 raw.swap 或 math.size64 的 swap 函数手动转换。

**函数对比：**

有关的 Python 函数与 aardio 函数的对应关系如下。

| Python 函数 | aardio 函数 |
| --- | --- |
| struct.pack | raw.pack |
| struct.pack_into | raw.pack.into | 
| struct.unpack | raw.pack.unpack | 
| struct.unpack_from 返回多值 | raw.convert 返回单个结构体 | 
| struct.calcsize | raw.sizeof 或 raw.calcsize | 
| struct.iter_unpack |raw.pack.each |

raw.pack, raw.pack.unpack 与 Python 相同处理的都是单个非数组值，
而 raw.pack.unpackArray,raw.pack.getStruct,raw.pack.getCode 都将指定重复次数的格式化字符处理为数组字段。
例如 raw.pack.getCode("@10H") 会返回包含结构体声明的 aardio 代码 `{ WORD field1[10]; }` 。

raw.pack.getCode 将 Python 的二进制格式化串转换为 aardio 结构体声明，
「aardio 工具 » 转换工具 » 原生类型转换」就是调用 raw.pack.getCode 转换二进制格式化串。

注意 raw.pack 返回的是 buffer 而不是字符串，在 aardio 里大部份函数通常可以用 buffer 替代字符串参数。
可以用 tostring(buffer) 将 buffer 转换为字符串。

**格式化字符：**

完整的格式化字符请查看 Python 文档，下面仅说明 aardio 中需要注意的一些格式。

- `s` 格式打包时可输入字符串或 buffer，解包时返回字符串，
aardio 中字符串也是二进制兼容的，都可以作为字节数组使用。

	`s` 格式打包时，不需要预先处理字符串的长度，
	raw.pack 会自动截断超出长度的部分，不足的部分会自动填充为 0。
	这是因为 raw.pack 底层基于 aardio 的结构体，而结构体自动就会处理这些问题。

    `s` 格式对应 Python 中的字节串（bytes）。
    在 aardio 与 Python 交互时，aardio 也会将 Python 字节串转换为 aardio 中的 buffer 。

    > aardio 中的 buffer 是可读写的，而 Python 字节串是只读的。

    可以将 Python 格式串先转换为 aardio 结构体，
    在结构体中 byte [] 类型字段默认处理为字符串值。
    如果值预先指定为 buffer 类型则解包时也会填充数据到原来的 buffer 中。
    如果值预先指定数组，则解包时会生成一个新的数组。

    在 Python 中 `s` 格式打包时需经预先处理长度，翻译为 aardio 代码就是这样写：

    ```aardio
	import raw.pack;
	var variableLengthString = "abcd"
	var size = 5;

	var fixedSizeString;

	//使用定长字符串
	if(#variableLengthString < size ) {
		fixedSizeString = variableLengthString + string.repeat(size-#variableLengthString) 
	}
	else{
		fixedSizeString = string.left(variableLengthString,size)
	}

	var buf = raw.pack("<5sb",variableLengthString,3);
	```

	上面的代码利用 buffer 的定长特性可以简化如下：

	```aardio 
	var fixedSizeBuffer = raw.buffer(size,variableLengthString)
	buf = raw.pack("<5sb",fixedSizeBuffer,3) //参数里字符串与 buffer 可以互换
	```

	但其实 raw.pack 本就可以将字符串或 buffer 自动转换为定长数据，
	所以可以直接写：

	```aardio 
	buf = raw.pack("<5sb",variableLengthString/*太长太短都会自动处理*/,3)
	```

	raw.pack 底层是基于 aardio 的结构体打包数据，
	aardio 结构体里的数组字段都不要求传入定长数组，太长太短 aardio 都会自动处理。
	所以处理这类问题，用 aardio 可以少写很多代码。

- `p` 格式在 aardio 中作为 `s` 格式处理。  
`p` 格式的唯一区别是第一个字节记录了长度，aardio 不会移除这个长度标记，也不会清除尾部的填充字节。
这种格式现在基本不太可能用到，可以忽略。
- `Q` 格式表示无符号 64 位整数，在 aardio 中解包时返回的是 math.size64 对象。
aardio 使用 math.size64 对象存储 64 位无符号整数，使用 tonumber 可以将其转换为普通的 64 位浮点数。
- `?` 格式在 aardio 中处理为 `byte` 类型，这个类型原本表示单字节 bool 类型，
但是 aardio 原生类型的 bool 类型是 4 字节，所以 `?` 以单字节 `byte` 替代。
aardio 中以 0 为 false，非 0 数值为 true，所以在使用上并没有太大区别。可以用双冒号 `!!` 将数值转换为 aardio 中的 boolean 类型。

</p></details>

[范例代码](https://www.aardio.com/zh-cn/docs/examples/aardio/Raw/raw.pack.html)

## raw 成员列表 <a id="raw" href="#raw">&#x23;</a>

### raw.pack(format,...) <a id="raw.pack" href="#raw.pack">&#x23;</a>
参数 @format 指定格式化字符串。  
其他不定个数的参数指定待打包的值，也可以传入包含多个参数的单个数组参数。  
成功返回字节串（ buffer 类型 ），  
失败返回 null,错误信息。  

为了与 Python 的用法保持一致，  
每个打包解包的参数都必须是单个非数组值（数值、字符串、buffer 等）。  
但改用 getStruct 或 getCode 可以得到支持数组的 aardio 结构体声明。  
将结构体作为参数就以用 raw.convert 解包或调用 raw.buffer 或 raw.tostring 打包。

## raw.pack 成员列表 <a id="raw.pack" href="#raw.pack">&#x23;</a>

用于二进制打包的库。  
兼容 Python struct.pack 格式化字符。  
raw.pack 与 raw.pack.unpack 会自动处理字节序。  
仅 `>` 与 `!` 开始的大端序与 aardio 的默认字节序不同需要转换。  

导入此库与 string.builder 库可使用 string.builder 的 pack 函数连续或批量打包。  

建议应 raw.pack.getCode 获取与打包解包格式化字符串一致的结构体声明，  
然后直接使用 raw.convert 解包，使用 raw.buffer 或 raw.tostring 打包。

### raw.pack.calcsize(format) <a id="raw.pack.calcsize" href="#raw.pack.calcsize">&#x23;</a>
raw.pack.sizeof 函数的别名。  
根据参数 @format 指定的格式化字符串计算打包后的字节长度。  
失败返回 0

### raw.pack.convert(format,buffer,offset) <a id="raw.pack.convert" href="#raw.pack.convert">&#x23;</a>
参数 @format 指定格式化字符串。  
参数 @buffer 指定需要解包的 buffer 或者字符串。  
可选用 @offset 参数指定偏移字节数，默认为 0。  
成功返回解包后的结构体对象（指定重复次数的格式字符转为数组） ，失败返回 null,错误信息。

### raw.pack.each(format,buffer,offset=0) <a id="raw.pack.each" href="#raw.pack.each">&#x23;</a>

```aardio
for count,items in raw.pack.each("<10s2HI",buffer){  
	/*  
解包迭代器，每次都返回包含所有字段的数组。  
不展开数组字段（ 例如 "2H" 格式化为 WORD[] 数组 ）  

相当于循环调用 raw.pack.unpackArray 函数。  
第一次循环只要 buffer 的长度大于 1 就会执行。  
后续会安全地检测剩下的长度是否足够解包，长度不够时退出循环。  

参数 @format 指定格式化字符串。  
兼容 Python struct.unpack 格式化字符。  
参数 @buffer 指定需要解包的 buffer 或者字符串。  
可选用 @offset 参数指定偏移字节数，默认为 0。	  
*/  
}
```

### raw.pack.getCode(format) <a id="raw.pack.getCode" href="#raw.pack.getCode">&#x23;</a>
根据参数 @format 指定的格式化字符串生成创建结构体的 aardio 代码，支持数组字段。  
失败返回 null,错误信息。  

此函数调用 raw.pack.getStruct 获取结构体并转换为代码，  
细节请参考该函数说明。

### raw.pack.getStruct(format) <a id="raw.pack.getStruct" href="#raw.pack.getStruct">&#x23;</a>
根据参数 @format 指定的格式化字符串生成结构体对象，支持数组字段。  
无对齐时 _struct_aligned 字段值为 1，否则遵守默认的结构体对齐规则。  
无对齐（紧凑结构）时如果巧合了自动对齐规则，则不会添加 _struct_aligned 字段。  
成功返回结构体，失败返回 null,错误信息。

### raw.pack.into(format,buffer,offset,...) <a id="raw.pack.into" href="#raw.pack.into">&#x23;</a>
参数 @format 指定格式化字符串。  
buffer 指定缓冲区( buffer 类型字节串 ) 对象，传 null 值则创建新的 buffer。  
offset 指定写入位置的字节偏移量，默认为 0。  
其他不定个数的参数指定待打包的值，也可以传入包含多个参数的单个数组参数。  
成功返回字节串（ buffer 类型 ），  
失败返回 null,错误信息。  

为了与 Python 的用法保持一致，  
每个打包解包的参数都必须是单个非数组值（数值、字符串、buffer 等）。  
但改用 getStruct 或 getCode 可以得到支持数组的 aardio 结构体声明。  
将结构体作为参数就以用 raw.convert 解包或调用 raw.buffer 或 raw.tostring 打包。

### raw.pack.reverse(buffer,index,size) <a id="raw.pack.reverse" href="#raw.pack.reverse">&#x23;</a>
原地转换字节序。  
参数 buffer 指定字节串（ buffer 类型 ）。  
此函数不会检查参数 @buffer 的类型，调用者有责任传入正确的类型。  
参数 @index 指定开始转换的索引，起始索引为 1。  
参数 @size 指定要转换的字节长度。

### raw.pack.sizeof(format) <a id="raw.pack.sizeof" href="#raw.pack.sizeof">&#x23;</a>
根据参数 @format 指定的格式化字符串计算打包后的字节长度。  
失败返回 0

### raw.pack.unpack(format,buffer,offset) <a id="raw.pack.unpack" href="#raw.pack.unpack">&#x23;</a>
参数 @format 指定格式化字符串。  
兼容 Python struct.unpack 格式化字符。  
参数 @buffer 指定需要解包的 buffer 或者字符串。  
可选用 @offset 参数指定偏移字节数，默认为 0。  
顺序返回解包成功的一个或多个值（指定重复次数的格式字符返回多个值而非数组）。

### raw.pack.unpackArray(format,buffer,offset) <a id="raw.pack.unpackArray" href="#raw.pack.unpackArray">&#x23;</a>
参数 @format 指定格式化字符串。  
兼容 Python struct.unpack 格式化字符。  
参数 @buffer 指定需要解包的 buffer 或者字符串。  
可选用 @offset 参数指定偏移字节数，默认为 0。  

此函数默认将指定重复次数的格式字符解包为单个数组值，  
如果参数 @4 为 false 则展开数组为多个值  

成功返回一个包含所有解包值的数组，失败无返回值。
