जब iOS पर gzip संकुचित डेटा को बढ़ाने के लिए कैसे पर खोजते समय, निम्न विधि परिणामों की संख्या में प्रकट होता है:क्या यह इस gzip inflate विधि में एक बग है?
- (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;
}
लेकिन मैं डेटा के कुछ उदाहरण (पायथन के gzip module के साथ एक Linux मशीन पर हवा निकाल) का सामना करना पड़ा कि आईओएस पर चल रही यह विधि बढ़ने में विफल रही है। यहां क्या हो रहा है:
जबकि लूप inflate() रिटर्न के अंतिम पुनरावृत्ति में Z_BUF_ERROR और लूप निकल गया है। लेकिन inflateEnd(), जिसे लूप के बाद बुलाया जाता है, Z_OK देता है। कोड तब मानता है कि चूंकि() कभी भी Z_STREAM_END वापस नहीं आया, मुद्रास्फीति विफल रही और शून्य वापस आ गई।
इस पेज के अनुसार, http://www.zlib.net/zlib_faq.html#faq05 Z_BUF_ERROR एक गंभीर त्रुटि नहीं है, और सीमित उदाहरण के साथ मेरी परीक्षणों से पता चलता है कि डेटा को सफलतापूर्वक फुलाया अगर inflateEnd() रिटर्न Z_OK है, भले ही बढ़ के अंतिम कॉल() नहीं लौटाया Z_OK। ऐसा लगता है जैसे inflateEnd() डेटा के आखिरी हिस्से को भरने के लिए समाप्त हुआ।
मुझे संपीड़न और जीजीआईपी कैसे काम करता है, इसके बारे में बहुत कुछ नहीं पता, इसलिए मुझे यह समझने में संकोच नहीं है कि यह क्या करता है पूरी तरह से समझता है। मैं आशा करता हूं कि इस विषय के बारे में अधिक जानकारी वाले किसी को उपरोक्त कोड में इस संभावित तर्क दोष पर कुछ प्रकाश डाला जा सकता है, और इसे ठीक करने का एक तरीका सुझाता है। कि एक ही समस्या से ग्रस्त लगता है
एक अन्य विधि यह है कि गूगल अप बदल जाता है, यहां पाया जा सकता: https://github.com/nicklockwood/GZIP/blob/master/GZIP/NSData%2BGZIP.m
संपादित करें:
इसलिए, यह एक बग है! अब, हम इसे कैसे ठीक करें? नीचे मेरा प्रयास है। कोड समीक्षा, कोई भी?
- (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;
}
संपादित करें 2:
यहां एक नमूना Xcode प्रोजेक्ट कि इस मुद्दे को मैं में चल रहा हूँ दिखाता है Deflate सर्वर साइड पर होता है और डेटा बेस 64 और यूआरएल के माध्यम से ले जाया जा रहा से पहले इनकोडिंग है। एचटीटीपी। मैंने ViewController.m में यूआरएल एन्कोडेड बेस 64 स्ट्रिंग को एम्बेड किया है।
https://dl.dropboxusercontent.com/u/38893107/gzip/binary.zip
यह वह जगह है: यूआरएल-डिकोड और बेस 64-डिकोड और साथ ही अपने gzipInflate तरीकों
https://dl.dropboxusercontent.com/u/38893107/gzip/GZIPTEST.zip
यहाँ बाइनरी फ़ाइल के रूप में अजगर gzip पुस्तकालय द्वारा हवा निकाल है NSDataExtension.m में हैं URL ने बेस 64 स्ट्रिंग को एन्कोड किया जो HTTP पर ले जाया जाता है: https://dl.dropboxusercontent.com/u/38893107/gzip/urlEncodedBase64.txt
यदि जीजीआईपी स्ट्रीम पूर्ण नहीं होता है तो प्रयास अनंत लूप में जाता है। –
वैसे, "binary.zip" एक ज़िप फ़ाइल नहीं है। यह एक gzip फ़ाइल है। नाम "binary.gz" होना चाहिए। –
यूआरएल binary.zip (जिसे binary.gz कहा जाना चाहिए) को डीकोड करता है, और मेरे उत्तर में प्रदान किया गया कोड ठीक से 221213 बाइट टेक्स्ट फ़ाइल में डिकंप्रेस करता है। मैंने यह देखने के लिए आपके कोड को नहीं देखा कि क्या गलत है - यह आपका काम है। –