Khi tìm kiếm trên làm thế nào để thổi phồng gzip dữ liệu nén trên iOS, các phương pháp sau đây xuất hiện trong số kết quả:Đây có phải là lỗi trong phương pháp thổi phồng gzip này không?
- (NSData *)gzipInflate
{
if ([self length] == 0) return self;
unsigned full_length = [self length];
unsigned half_length = [self length]/2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[self bytes];
strm.avail_in = [self length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
while (!done)
{
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length])
[decompressed increaseLengthBy: half_length];
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = [decompressed length] - strm.total_out;
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
if (status == Z_STREAM_END) done = YES;
else if (status != Z_OK) break;
}
if (inflateEnd (&strm) != Z_OK) return nil;
// Set real length.
if (done)
{
[decompressed setLength: strm.total_out];
return [NSData dataWithData: decompressed];
}
else return nil;
}
Nhưng tôi đã đi qua một số ví dụ về dữ liệu (xì hơi trên một máy Linux với Python của gzip module) rằng phương pháp này đang chạy trên iOS không thể tăng cao. Đây là những gì đang xảy ra:
Trong lần lặp cuối cùng của vòng lặp while() trả về Z_BUF_ERROR và vòng lặp được thoát. Nhưng inflateEnd(), được gọi sau vòng lặp, trả về Z_OK. Mã sau đó giả định rằng vì inflate() không bao giờ trả về Z_STREAM_END, lạm phát không thành công và trả về giá trị rỗng. Theo trang này, http://www.zlib.net/zlib_faq.html#faq05 Z_BUF_ERROR không phải là một lỗi nghiêm trọng, và các thử nghiệm của tôi với các ví dụ hạn chế cho thấy rằng dữ liệu được thổi phồng thành công nếu inflateEnd() trả về Z_OK, mặc dù cuộc gọi cuối cùng của inflate() không trả về Z_OK. Có vẻ như inflateEnd() đã hoàn thành việc tăng lượng dữ liệu cuối cùng.
Tôi không biết nhiều về nén và cách hoạt động của gzip, vì vậy tôi do dự khi thực hiện các thay đổi đối với mã này mà không hiểu đầy đủ về những gì nó thực hiện. Tôi hy vọng một người nào đó có nhiều kiến thức về chủ đề này có thể làm sáng tỏ về lỗ hổng logic tiềm ẩn này trong đoạn mã trên, và đề xuất cách khắc phục nó.
Một phương pháp mà Google lần lượt lên, điều đó dường như gặp phải vấn đề tương tự có thể được tìm thấy ở đây: https://github.com/nicklockwood/GZIP/blob/master/GZIP/NSData%2BGZIP.m
Edit:
Vì vậy, nó là một lỗi! Bây giờ, làm thế nào để chúng tôi sửa chữa nó? Dưới đây là nỗ lực của tôi. Đánh giá mã, có ai không?
- (NSData *)gzipInflate
{
if ([self length] == 0) return self;
unsigned full_length = [self length];
unsigned half_length = [self length]/2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
int status;
z_stream strm;
strm.next_in = (Bytef *)[self bytes];
strm.avail_in = [self length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
do
{
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length])
[decompressed increaseLengthBy: half_length];
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = [decompressed length] - strm.total_out;
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
switch (status) {
case Z_NEED_DICT:
status = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
(void)inflateEnd(&strm);
return nil;
}
} while (status != Z_STREAM_END);
(void)inflateEnd (&strm);
// Set real length.
if (status == Z_STREAM_END)
{
[decompressed setLength: strm.total_out];
return [NSData dataWithData: decompressed];
}
else return nil;
}
Chỉnh sửa 2:
Dưới đây là một dự án mẫu Xcode minh họa vấn đề tôi đang chạy trong The deflate xảy ra ở phía máy chủ và dữ liệu là base64 và url được mã hóa trước khi được vận chuyển qua. HTTP. Tôi đã nhúng chuỗi base64 được mã hóa url trong ViewController.m. Url-decode và base64-decode cũng như phương pháp gzipInflate bạn đang ở trong NSDataExtension.m
https://dl.dropboxusercontent.com/u/38893107/gzip/GZIPTEST.zip
Dưới đây là các tập tin nhị phân như xì hơi bởi thư viện python gzip:
https://dl.dropboxusercontent.com/u/38893107/gzip/binary.zip
Đây là chuỗi base64 được mã hóa URL được chuyển qua HTTP: https://dl.dropboxusercontent.com/u/38893107/gzip/urlEncodedBase64.txt
Nỗ lực đi vào vòng lặp vô hạn nếu luồng gzip chưa hoàn thành. –
Nhân tiện, "binary.zip" không phải là tệp zip. Nó là một tệp gzip. Tên phải là "binary.gz". –
URL giải mã thành binary.zip (được gọi là binary.gz) và mã tôi đã cung cấp trong câu trả lời của tôi giải nén chính xác tệp đó thành tệp văn bản byte 221213. Tôi đã không nhìn vào mã của bạn để xem có gì sai - đó là công việc của bạn. –