如何在日本机器上使用 zlib?
我试图通过使用 zlib 来压缩字符串(我已经用当前的 1.2.3 尝试过此代码zlib 版本和 zlib 1.1.3)。 除非在日本机器上运行,否则我的代码可以正常工作。压缩文件后,我对其进行加密。解密成功,但调用 uncompress 返回 -3(Z_DATA_ERROR
,表示输入数据已损坏)。由于没有记录错误,我知道没有抛出异常,并且压缩函数返回 0(Z_OK
,意味着它有效)。
因此,我怀疑问题在于 sCompressed
字符串在“sCompressed = Left(sCompressed, lcompressedlen)
”行或“encryptedData”行上失去完整性.Content = s压缩
。”或者,VB6 可能会在调用 compress
期间执行一些stupid 对 sCompressed
的内容有帮助的事情。我知道这个函数的返回值稍后不会被破坏,因为这会破坏解密,但效果很好。
Public Function EncryptString(ByVal Definition As String) As String
On Error GoTo ErrorHandler
Dim encryptedData As New CAPICOM.encryptedData
encryptedData.SetSecret KEY_CONST
Dim lStringLen As Long
Dim lcompressedlen As Long
Dim sCompressed As String
Dim lReturn As Long
Dim tstpost As String
lStringLen = Len(Definition)
lcompressedlen = (lStringLen * 1.01) + 13
sCompressed = Space(lcompressedlen)
lReturn = compress(sCompressed, lcompressedlen, Definition, lStringLen)
If lReturn <> 0 Then
sCompressed = "Error: " & CStr(lReturn)
'<LOG ERROR>'
Else
sCompressed = Left(sCompressed, lcompressedlen)
End If
encryptedData.Content = sCompressed
encryptedData.Algorithm.Name = CAPICOM_ENCRYPTION_ALGORITHM_3DES
EncryptXmlString = encryptedData.Encrypt
Exit Function
ErrorHandler:
'<LOG ERROR>'
Resume Next
End Function
结论:
我最终让程序给出错误消息,并在具有可疑字符集的计算机上运行时退出。这个错误很可能仍然存在于一些设置上,也很可能在某些触发错误的设置上不存在。然而,由于目标受众是说英语的人,因此通过土耳其测试的重要性不足以证明在这方面花费更多时间是合理的。
I am attempting to compress a string via use of zlib (I've tried this code with current 1.2.3 version of zlib and with zlib 1.1.3). My code works correctly, unless run on a Japanese machine. After compressing a file, I am encrypting it. The decryption is successful, but the call to uncompress returns -3 (Z_DATA_ERROR
, meaning the input data was corrupted). As there are no errors being logged, I know that no exceptions are being thrown, and that the compression function is returning 0 (Z_OK
, meaning it worked).
Thus, I suspect the problem is that the sCompressed
string is losing integrity on either the line "sCompressed = Left(sCompressed, lcompressedlen)
" or the line "encryptedData.Content = sCompressed
." Alternatively, VB6 might be doing something stupid helpful to the contents of sCompressed
during the call to compress
. I know that the return value of this function is not being corrupted later, because that would have broken decryption, which works fine.
Public Function EncryptString(ByVal Definition As String) As String
On Error GoTo ErrorHandler
Dim encryptedData As New CAPICOM.encryptedData
encryptedData.SetSecret KEY_CONST
Dim lStringLen As Long
Dim lcompressedlen As Long
Dim sCompressed As String
Dim lReturn As Long
Dim tstpost As String
lStringLen = Len(Definition)
lcompressedlen = (lStringLen * 1.01) + 13
sCompressed = Space(lcompressedlen)
lReturn = compress(sCompressed, lcompressedlen, Definition, lStringLen)
If lReturn <> 0 Then
sCompressed = "Error: " & CStr(lReturn)
'<LOG ERROR>'
Else
sCompressed = Left(sCompressed, lcompressedlen)
End If
encryptedData.Content = sCompressed
encryptedData.Algorithm.Name = CAPICOM_ENCRYPTION_ALGORITHM_3DES
EncryptXmlString = encryptedData.Encrypt
Exit Function
ErrorHandler:
'<LOG ERROR>'
Resume Next
End Function
Conclusion:
I ended up making the program give an error message and quit if run on a machine with a suspicious character set. It is quite likely that this bug still exists on a few settings and also likely that it does not exist on some of the settings that trigger the error. However, since the target audience is English speakers, passing the Turkey Test is not important enough to justify actually spending more time on this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您打算传递字节数组时停止使用字符串?
当然当您像这里一样使用字符串时,您将获得自动 ANSI 转换和数据重新复制。
Stop using a String when you mean to pass a Byte array?
Of course you're going to get automatic ANSI conversions and data recopying when you use Strings as you do here.
鲍勃是正确的。这些只是我对他的回答的脚注。请注意,我完全不熟悉 zlib - 我假设您正在使用
Declare
进行compress
调用 DLL。使用字符串而不是字节数组并不意味着您可以避免 ANSI 转换。它通常仅意味着 VB6 隐式执行转换,而您无法控制它 - 例如,当您使用
Declare
语句调用 DLL 并传递字符串时。从压缩返回的神奇字节序列可能不是日语代码页上的有效“ANSI”字符串。该代码页的 MSDN 表中未定义某些字符序列。如果您使用
Declare
语句调用 DLL,并期望将字符串返回到 sCompressed,则该 DLL 最好将有效的“ANSI”字符串写入相应的缓冲区。如果它写入无效的字节序列,则可能会发生任何情况。您在中文(936 和 950)和韩语(949)方面也会遇到麻烦。您所描述的情况很可能会发生:当
compress
返回时,无效的字节序列可能会转换为“Unicode”字符串,而不会报告错误 - 也许是与您的第一部分匹配的截断的 Unicode 字符串字节序列。然后,当您稍后尝试解压缩时,该 Unicode 字符串将转换回 ANSI 字符串,并且它与您开始时的原始字节序列不匹配。根本不可能匹配啊没有可能的 Unicode 字符串会转换为代码页 932 上的“ANSI”字符串,作为不是有效字符串的字节序列。这里有一些关于 VB6 的 Unicode 实现的可怕混乱的更多信息:免费章节来自 Michael Kaplan 的优秀著作 Internationalization With Visual Basic
我还怀疑您可能将字符串中的字符数与其在 ANSI 表示中占用的字节数混淆了(我对
lStringLen
和lcompressedlen
表示怀疑)。同样,日语是双字节字符集,因此 ANSI 字符串对于 N 个字符可能最多需要 2*N 个字节。Bob is right. These are just my footnotes to his answer. Be warned I'm totally unfamiliar with zlib - I'm assuming you're calling a DLL using a
Declare
forcompress
.Using a String instead of a Byte array doesn't mean you avoid the ANSI conversion. It often just means VB6 does the conversion implicitly and you can't control it - for instance when you call a DLL with a
Declare
statement and pass a string.It's possible that the magic sequence of bytes returned from the compression is not a valid "ANSI" string on the Japanese code page. Some character sequences are undefined on the MSDN table for that code page. If you are calling a DLL with a
Declare
statement and expecting a string to be returned into sCompressed, that DLL had better write a valid "ANSI" string into the corresponding buffer. If it writes an invalid sequence of bytes, anything might happen. You will also have trouble on Chinese (936 and 950) and Korean (949).What you're describing might well happen: when
compress
returns the invalid sequence of bytes might be converted into a "Unicode" string without errors being reported - perhaps a truncated Unicode string that matches the first portion of your byte sequence. Then, when you later attempt to decompress, that Unicode string is converted back into an ANSI string, and it doesn't match the original byte sequence you started from. It can't possibly match. There's no possible Unicode string that will convert to an "ANSI" string on code page 932 as a sequence of bytes that isn't a valid string.Here's some more info on the terrible mishmash that is VB6's implementation of Unicode: a free chapter from Michael Kaplan's excellent book Internationalization With Visual Basic
I also suspect you may be confusing the number of characters in a string with the number of bytes it occupies in ANSI representation (I'm suspicious of
lStringLen
andlcompressedlen
). Again, Japanese is a double-byte character set so the ANSI string may take up to 2*N bytes for N characters.