136 lines
3.9 KiB
Objective-C
136 lines
3.9 KiB
Objective-C
//
|
|
// GZIP.m
|
|
//
|
|
// Version 1.3.2
|
|
//
|
|
// Created by Nick Lockwood on 03/06/2012.
|
|
// Copyright (C) 2012 Charcoal Design
|
|
//
|
|
// Distributed under the permissive MIT license
|
|
// Get the latest version from here:
|
|
//
|
|
// https://github.com/nicklockwood/GZIP
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
|
|
#import "NSData+GZIP.h"
|
|
#import <zlib.h>
|
|
|
|
|
|
#pragma clang diagnostic ignored "-Wcast-qual"
|
|
|
|
|
|
@implementation NSData (GZIP)
|
|
|
|
- (NSData *)gzippedDataWithCompressionLevel:(float)level
|
|
{
|
|
if (self.length == 0 || [self isGzippedData])
|
|
{
|
|
return self;
|
|
}
|
|
|
|
z_stream stream;
|
|
stream.zalloc = Z_NULL;
|
|
stream.zfree = Z_NULL;
|
|
stream.opaque = Z_NULL;
|
|
stream.avail_in = (uint)self.length;
|
|
stream.next_in = (Bytef *)(void *)self.bytes;
|
|
stream.total_out = 0;
|
|
stream.avail_out = 0;
|
|
|
|
static const NSUInteger ChunkSize = 16384;
|
|
|
|
NSMutableData *output = nil;
|
|
int compression = (level < 0.0f)? Z_DEFAULT_COMPRESSION: (int)(roundf(level * 9));
|
|
if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK)
|
|
{
|
|
output = [NSMutableData dataWithLength:ChunkSize];
|
|
while (stream.avail_out == 0)
|
|
{
|
|
if (stream.total_out >= output.length)
|
|
{
|
|
output.length += ChunkSize;
|
|
}
|
|
stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out;
|
|
stream.avail_out = (uInt)(output.length - stream.total_out);
|
|
deflate(&stream, Z_FINISH);
|
|
}
|
|
deflateEnd(&stream);
|
|
output.length = stream.total_out;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
- (NSData *)gzippedData
|
|
{
|
|
return [self gzippedDataWithCompressionLevel:-1.0f];
|
|
}
|
|
|
|
- (NSData *)gunzippedData
|
|
{
|
|
if (self.length == 0 || ![self isGzippedData])
|
|
{
|
|
return self;
|
|
}
|
|
|
|
z_stream stream;
|
|
stream.zalloc = Z_NULL;
|
|
stream.zfree = Z_NULL;
|
|
stream.avail_in = (uint)self.length;
|
|
stream.next_in = (Bytef *)self.bytes;
|
|
stream.total_out = 0;
|
|
stream.avail_out = 0;
|
|
|
|
NSMutableData *output = nil;
|
|
if (inflateInit2(&stream, 47) == Z_OK)
|
|
{
|
|
int status = Z_OK;
|
|
output = [NSMutableData dataWithCapacity:self.length * 2];
|
|
while (status == Z_OK)
|
|
{
|
|
if (stream.total_out >= output.length)
|
|
{
|
|
output.length += self.length / 2;
|
|
}
|
|
stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out;
|
|
stream.avail_out = (uInt)(output.length - stream.total_out);
|
|
status = inflate (&stream, Z_SYNC_FLUSH);
|
|
}
|
|
if (inflateEnd(&stream) == Z_OK)
|
|
{
|
|
if (status == Z_STREAM_END)
|
|
{
|
|
output.length = stream.total_out;
|
|
}
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
- (BOOL)isGzippedData
|
|
{
|
|
const UInt8 *bytes = (const UInt8 *)self.bytes;
|
|
return (self.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
|
|
}
|
|
|
|
@end
|