Decompressing/inflating zlib-compressed 没有 adler32 校验和的数据
Decompressing/inflating zlib-compressed data without adler32 checksum
更新 2(最新)
情况如下:
一个外国应用程序正在以这种格式存储 zlib 压缩(压缩)数据:
78 9C BC (...data...) 00 00 FF FF
- 我们称它为 DATA1
如果我使用原始 XML 文件并在 Java 或 Tcl 中将其压缩,我得到:
78 9C BD (...data...) D8 9F 29 BB
- 我们称它为 DATA2
- DATA2 中的最后 4 个字节肯定是 Adler-32 校验和,在 DATA1 中被替换为 zlib FULL-SYNC 标记(为什么?我不知道)。
- 第 3 个字节的值不同 1。
- DATA1 和 DATA2 之间的
(...data...)
相等。
- 现在是最有趣的部分:如果我更新 DATA1,将第 3 个字节从
BC
更改为 BD
,则保留最后 8 个字节不变(所以0000FFFF
) 并用 new Inflater(true)
(https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/zip/Inflater.html#%3Cinit%3E(boolean)) 膨胀此数据,我能够正确解码它! (因为这种模式下的Inflater不需要zlib Adler-32 checksum和zlib header)
问题:
- 为什么将
BC
更改为 BD
有效?在所有情况下都安全吗?我检查了几个案例,每次都工作。
- 为什么任何应用程序都会输出
BC
的不正确 (?) 缩小值?
- 为什么应用程序会以 zlib header (
78 9C
) 开头,但不会生成兼容的 zlib 结构(FLUSH-SYNC 而不是 Adler-32)?它不是一个小型的业余爱好应用程序,而是一个广泛使用的商业应用程序(我会说有数十万商业用户)。
### 更新 1(旧)
经过进一步分析,我似乎有一个 zlib-compressed 字节数组错过了最终校验和 (adler32)。
根据 RFC 1950,正确的 zlib 格式必须以 adler32 校验和结尾,但出于某种原因,我使用的数据集有 zlib 字节,缺少该校验和。它总是以 00 00 FF FF
结尾,在 zlib 格式中是 SYNC FLUSH 的标记。一个完整的zlibobject,后面应该有adler32,但是有none.
这样的数据应该还是可以膨胀的吧?
如前所述(在下面的原始问题中),我试图将此字节数组传递给 Java inflater(我也尝试过使用 Tcl 中的一个),但没有成功。生成这些字节的应用程序能够以某种方式正确读取它(如下文所述)。
如何解压?
原始问题,更新前:
上下文
有一个应用程序(封闭源代码)连接到 MS SQL 服务器并将压缩的 XML 文档存储在 image
类型的列中。此应用程序 - 在请求时 - 可以将文档导出到本地磁盘上的常规 XML 文件,因此我可以直接在数据库中访问纯文本 XML 数据以及压缩数据.
问题
我希望能够使用我自己的连接到 SQL 服务器的代码解压缩此列中的任何值。
问题是它是某种奇怪的 zlib 格式。它确实以典型的 zlib header 字节 (78
9C
) 开头,但我无法解压缩它(我使用了 Java Decompress a string compressed with zlib deflate 中描述的方法)。
整个数据看起来像789CBC58DB72E238...7E526E7EFEA5E3D5FF0CFE030000FFFF
(当然,点意味着里面更多的字节——总共1195)。
我已经尝试过的
引起我注意的是结尾0000FFFF
,但即使我截断它,解压仍然失败。我实际上试图解压缩它从末尾截断所有字节数(在循环中,每次迭代切掉最后一个字节) - none 迭代也有效。
我还将原始 XML 文件压缩成 zlib 字节,看看它看起来如何,除了 2 个 zlib header 字节,然后可能还有 5-6 个字节,剩下的的数据是不同的。输出字节数也不同(更小),但不多(大约 1180 对 1195 字节)。
deflate 方面的不同之处在于,外部应用程序正在使用 Z_SYNC_FLUSH
或 Z_FULL_FLUSH
将目前提供的数据刷新到压缩流中。您正在(正确地)使用 Z_FINISH
结束流。在第一种情况下,您最终会得到一个未终止且没有检查值的部分放气流。相反,它只是以一个空的存储块结束,这导致最后的 00 00 ff ff
字节。在第二种情况下,您最终会得到一个完整的 deflate 流和一个带有检查值的 zlib 预告片。在这种情况下,恰好只有一个deflate块(数据肯定比较小),所以第一个块是最后一个块,并用1
标记为第一个字节的低位.
您正在做的是在第一个块上设置最后一个块位。这通常并不总是有效,因为流可能有多个块。在这种情况下,需要设置流中间的其他一些位。
我猜您得到的是部分压缩数据,但不是全部。到目前为止,有一个允许传输数据的刷新,但通常随后会继续压缩和更多这样的刷新数据包。
(与#2相同的问题,相同的答案。)
更新 2(最新)
情况如下:
一个外国应用程序正在以这种格式存储 zlib 压缩(压缩)数据:
78 9C BC (...data...) 00 00 FF FF
- 我们称它为 DATA1
如果我使用原始 XML 文件并在 Java 或 Tcl 中将其压缩,我得到:
78 9C BD (...data...) D8 9F 29 BB
- 我们称它为 DATA2
- DATA2 中的最后 4 个字节肯定是 Adler-32 校验和,在 DATA1 中被替换为 zlib FULL-SYNC 标记(为什么?我不知道)。
- 第 3 个字节的值不同 1。
- DATA1 和 DATA2 之间的
(...data...)
相等。 - 现在是最有趣的部分:如果我更新 DATA1,将第 3 个字节从
BC
更改为BD
,则保留最后 8 个字节不变(所以0000FFFF
) 并用new Inflater(true)
(https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/zip/Inflater.html#%3Cinit%3E(boolean)) 膨胀此数据,我能够正确解码它! (因为这种模式下的Inflater不需要zlib Adler-32 checksum和zlib header)
问题:
- 为什么将
BC
更改为BD
有效?在所有情况下都安全吗?我检查了几个案例,每次都工作。 - 为什么任何应用程序都会输出
BC
的不正确 (?) 缩小值? - 为什么应用程序会以 zlib header (
78 9C
) 开头,但不会生成兼容的 zlib 结构(FLUSH-SYNC 而不是 Adler-32)?它不是一个小型的业余爱好应用程序,而是一个广泛使用的商业应用程序(我会说有数十万商业用户)。
经过进一步分析,我似乎有一个 zlib-compressed 字节数组错过了最终校验和 (adler32)。
根据 RFC 1950,正确的 zlib 格式必须以 adler32 校验和结尾,但出于某种原因,我使用的数据集有 zlib 字节,缺少该校验和。它总是以 00 00 FF FF
结尾,在 zlib 格式中是 SYNC FLUSH 的标记。一个完整的zlibobject,后面应该有adler32,但是有none.
这样的数据应该还是可以膨胀的吧?
如前所述(在下面的原始问题中),我试图将此字节数组传递给 Java inflater(我也尝试过使用 Tcl 中的一个),但没有成功。生成这些字节的应用程序能够以某种方式正确读取它(如下文所述)。
如何解压?
原始问题,更新前:
上下文
有一个应用程序(封闭源代码)连接到 MS SQL 服务器并将压缩的 XML 文档存储在 image
类型的列中。此应用程序 - 在请求时 - 可以将文档导出到本地磁盘上的常规 XML 文件,因此我可以直接在数据库中访问纯文本 XML 数据以及压缩数据.
问题
我希望能够使用我自己的连接到 SQL 服务器的代码解压缩此列中的任何值。
问题是它是某种奇怪的 zlib 格式。它确实以典型的 zlib header 字节 (78
9C
) 开头,但我无法解压缩它(我使用了 Java Decompress a string compressed with zlib deflate 中描述的方法)。
整个数据看起来像789CBC58DB72E238...7E526E7EFEA5E3D5FF0CFE030000FFFF
(当然,点意味着里面更多的字节——总共1195)。
我已经尝试过的
引起我注意的是结尾0000FFFF
,但即使我截断它,解压仍然失败。我实际上试图解压缩它从末尾截断所有字节数(在循环中,每次迭代切掉最后一个字节) - none 迭代也有效。
我还将原始 XML 文件压缩成 zlib 字节,看看它看起来如何,除了 2 个 zlib header 字节,然后可能还有 5-6 个字节,剩下的的数据是不同的。输出字节数也不同(更小),但不多(大约 1180 对 1195 字节)。
deflate 方面的不同之处在于,外部应用程序正在使用 Z_SYNC_FLUSH
或 Z_FULL_FLUSH
将目前提供的数据刷新到压缩流中。您正在(正确地)使用 Z_FINISH
结束流。在第一种情况下,您最终会得到一个未终止且没有检查值的部分放气流。相反,它只是以一个空的存储块结束,这导致最后的 00 00 ff ff
字节。在第二种情况下,您最终会得到一个完整的 deflate 流和一个带有检查值的 zlib 预告片。在这种情况下,恰好只有一个deflate块(数据肯定比较小),所以第一个块是最后一个块,并用1
标记为第一个字节的低位.
您正在做的是在第一个块上设置最后一个块位。这通常并不总是有效,因为流可能有多个块。在这种情况下,需要设置流中间的其他一些位。
我猜您得到的是部分压缩数据,但不是全部。到目前为止,有一个允许传输数据的刷新,但通常随后会继续压缩和更多这样的刷新数据包。
(与#2相同的问题,相同的答案。)