I am trying to decompress data using the ZLib in iPhone, but it always through error of "Invalid header Check".
To compress the data I am using the following in Java
Implementation: Standard Java implementation for Zlib
Deflator : java.util.zip.Deflater
version 1.45, 04/07/06
Compression level: BEST_COMPRESSION
In iPhone the following is the code for decompressing:
- (NSData *)zlibInflate
{
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 (inflateInit (&strm) != 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) {
NSLog(#"%s", strm.msg);
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;
}
Following is a sample compressed string:
xÚÝUko²Jþ~?ó?¥¾?¤?©?´ÚjCMX,Òµ?ª?µßVX¹È?¿.øë_?¯¶ZÏ%íùxHH&Ã<ÏÌ3ÌÎ
#2.ðE?ºqþpéEzÏ09IoÒ?ª? ?®?£àÌönì$brÛ#fl95?¿»a//Tçáò?¢?¿½
µ©ÊÃÉPÔ¼:8y¦ý.äÎ?µ?¥?¼y?©ã¯9ö?¥½?¢±ÝûwÛ?§ãga?©á8?¨?m\Õ?»6,'Îe?¬}(L}7ÆÅ6#gJ(¥7´s?¬d.ó,Ë°¦prßýÕÖ?
Below is the function for compresser:
public static byte[] compress(String s) {
Deflater comp = new Deflater();
//comp.setLevel(Deflater.BEST_COMPRESSION);
comp.setInput(s.getBytes());
comp.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(s.length());
// Compress the data
byte[] buf = new byte[1024];
try {
while (!comp.finished()) {
int count = comp.deflate(buf);
bos.write(buf, 0, count);
}
bos.close();
} catch (Exception e) {
//Log.d(TAG, e.getMessage());
e.printStackTrace();
}
// Get the compressed data
byte[] compressedData = bos.toByteArray();
// put in this fix for Symbol scanners
byte[] compressedDataForSymbol = mungeForSymbol(compressedData);
/*
* byte[] decompressedDataForSymbol =
* decompressedDataAfterSymbol(compressedDataForSymbol); // check they
* are the same for(int i=0;i<compressedData.length;i++) { if
* (compressedData[i] != decompressedDataForSymbol[i]) {
* //System.out.println("Error at " + i); } }
*/
return compressedDataForSymbol;
// return s.getBytes();
}
Using Java Deflater with default compression level creates output encoded data with header with first two bytes 0x78 0x9c. These are not used in IOS. Just remove the first two bytes and try the Inflate ie decompression in IOS. It should work.
I had faced the same issue, But i wanted data from IOS(compressed) to android(decompressed).
Related
Here is the data source, encoded by ISO-8859-1:
"x%DAe%91%C1%92%9B0%0C%86%9F%A5%3A%B3%C1%84%98%89%B9%F4%D0%F3%3EA%E9xd%5B%807%06S%23%B2%DD%EE%EC%BB%D7%24%E9%B4%9D%1E%3CcI%BF%A5O%BF%DF%21D%7B%D1%AF%23%21C%0BP%00%C7e%D5%26Et%16W%A6%04%ED%D7w%D8%BC%CB%D5s%D3%08%21T%16%AD6%26%82V%3Cn%BA%8Fi%DA%1B%EC%09%E2%DB%2B%A5%0A%C0e%E9%D1f%21%8C%CCK%DB%95%5D9%FA%80O%D5%E15%A2wq%1E%F6s%B0sW6%95%11%A7%DE%08el%D5%98S%D3H%A4%B3%B4u%AD%B0%E9%E5%09%0F%2F%CB%F0%D9O8%D0s%1C%D2%B1%2B%BFo%18%3C%BFue%25%C4%A7%AE%5C%FDOz%0A%7E%F2%DC%95gq%C9%99%1D%93%7E%40%5B%15%FB%8E%C8%3E%CE%19%E4%CB%E8g%CC%A5%D9%DB%CB%8C%D3%CE%26%A5%CC%89%40W%0A%D0%1E%B3%BC%0F8%40%3Bo%21%14%90b+%CDo%0B%DD%1A%E1%E6%7C%7C%DE%98%DC-%BCzG%BF%C3%BCz%22%0C%EC%27%FA%23%C0%8D%C7%982%E6%A3E%16e%A7%9D%1E%E3%1C%93%DEM%CD%F4b%9F%19%FC%95VF%BE%8B%B6%95%92%FE%D7Z%10%19r%B9%E8%87%F5w%BA5%26%BE3%27%1BW%D6%8F%25%B2%F5%7F%87%C7%EA%E3%5B%01%93%93%FA%FF%CF%05%7B%A6Z%2A%EC%8DR%27ekS%F7R%D6X%2BS%29stX%C1%C7%2F%7B%CD%B12"
I guess in swift, ISO-8859-1 is String.Encoding.isoLatin1
The content contained is
{"lock_wheat":"","topsSth":[{"uid":"8660009","score":0,"score_format":0,"setter":99,"appface":"http:hahaha","sex":1,"location":"China","nickname":"555","level":21,"flag":null,"role_type":1,"audioMuted":1,"videoMuted":0,"realtimeMuted":1,"authority_type":0,"head_honor_id":100021,"livestate":0,"user_score_format":"0","pk_score":null,"sort":21,"rcost_level":9,"cost_level":21}],"md5_tops_broadcaster":"666"}
PS: I edited some words above
I need to convert to the following Java code to Swift
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.Inflater;
public class HelloWorld {
public static String decompress(String data, String charset) throws UnsupportedEncodingException {
byte[] bytes = data.getBytes(charset);
byte[] output = new byte[0];
Inflater decompresser = new Inflater();
decompresser.reset();
decompresser.setInput(bytes);
ByteArrayOutputStream o = new ByteArrayOutputStream(bytes.length);
try {
byte[] buf = new byte[1024];
while (!decompresser.finished()) {
int i = decompresser.inflate(buf);
o.write(buf, 0, i);
}
output = o.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
o.close();
} catch (IOException e) {
e.printStackTrace();
}
}
decompresser.end();
return new String(output);
}
public static String decompress(String data) throws UnsupportedEncodingException {
String decodeTmp = URLDecoder.decode(data, "ISO-8859-1");
System.out.println(decodeTmp);
return decompress(decodeTmp, "ISO-8859-1");
}
public static void main(String[] args) {
String data = "x%DAe%91%C1%92%9B0%0C%86%9F%A5%3A%B3%C1%84%98%89%B9%F4%D0%F3%3EA%E9xd%5B%807%06S%23%B2%DD%EE%EC%BB%D7%24%E9%B4%9D%1E%3CcI%BF%A5O%BF%DF%21D%7B%D1%AF%23%21C%0BP%00%C7e%D5%26Et%16W%A6%04%ED%D7w%D8%BC%CB%D5s%D3%08%21T%16%AD6%26%82V%3Cn%BA%8Fi%DA%1B%EC%09%E2%DB%2B%A5%0A%C0e%E9%D1f%21%8C%CCK%DB%95%5D9%FA%80O%D5%E15%A2wq%1E%F6s%B0sW6%95%11%A7%DE%08el%D5%98S%D3H%A4%B3%B4u%AD%B0%E9%E5%09%0F%2F%CB%F0%D9O8%D0s%1C%D2%B1%2B%BFo%18%3C%BFue%25%C4%A7%AE%5C%FDOz%0A%7E%F2%DC%95gq%C9%99%1D%93%7E%40%5B%15%FB%8E%C8%3E%CE%19%E4%CB%E8g%CC%A5%D9%DB%CB%8C%D3%CE%26%A5%CC%89%40W%0A%D0%1E%B3%BC%0F8%40%3Bo%21%14%90b+%CDo%0B%DD%1A%E1%E6%7C%7C%DE%98%DC-%BCzG%BF%C3%BCz%22%0C%EC%27%FA%23%C0%8D%C7%982%E6%A3E%16e%A7%9D%1E%E3%1C%93%DEM%CD%F4b%9F%19%FC%95VF%BE%8B%B6%95%92%FE%D7Z%10%19r%B9%E8%87%F5w%BA5%26%BE3%27%1BW%D6%8F%25%B2%F5%7F%87%C7%EA%E3%5B%01%93%93%FA%FF%CF%05%7B%A6Z%2A%EC%8DR%27ekS%F7R%D6X%2BS%29stX%C1%C7%2F%7B%CD%B12";
try {
String dateNew = decompress(data);
System.out.println(dateNew);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is what I tried:
I am obstructed at this java line
String decodeTmp = URLDecoder.decode(data, "ISO-8859-1");
Here prints
xÚeÁ0
¥:³Á¹ôÐó>Aéxd[7S#²Ýîì»×$é´<cI¿¥O¿ß!D{ѯ#!C
PÇeÕ&EtW¦í×wؼËÕs!T6&V<nºiÚì âÛ+¥
ÀeéÑf!ÌKÛ]9úOÕá5¢wqös°sW6§elÕSÓH¤³´u°éå /ËðÙO8ÐsÒ±+¿o<¿ue%ħ®\ýOz
~òÜgqÉ~#[ûÈ>ÎäËègÌ¥ÙÛËÓÎ&¥Ì#W
г¼8#;o!b Ío
Ýáæ||ÞÜ-¼zG¿Ã¼z"
ì'ú#ÀÇ2æ£Ee§ãÞMÍôbüVF¾¶þ×Zr¹èõwº5&¾3'Ö%²õÇêã[úÿÏ{¦Z*ìR'ekS÷R
as for URLDecoder in Java, I don't know such thing in Swift.
Here is Objective - C solution:
as #Martin R said, zlib
as #Sulthan said, deprecated since iOS 9
#include <zlib.h>
#implementation NSData (Compression)
#pragma mark -
#pragma mark Zlib Compression routines
- (NSData *) zlibInflate
{
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 (inflateInit (&strm) != 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;
}
#end
#implementation NSString (ZlibData)
- (NSDictionary *)transformZLibData{
NSString *str = [self stringByReplacingOccurrencesOfString:#"+" withString:#"%20"];
NSString *latin1String = [str stringByReplacingPercentEscapesUsingEncoding:NSISOLatin1StringEncoding];
NSData *latin1Data = [latin1String dataUsingEncoding:NSISOLatin1StringEncoding];
NSData *inflateData = [latin1Data zlibInflate];
if (![inflateData isKindOfClass:[NSData class]] || inflateData.length < 1) {
return nil;
}
id jsonObj = [NSJSONSerialization JSONObjectWithData:inflateData options:NSJSONReadingAllowFragments error:nil];
NSLog(#"%#", jsonObj);
if (![jsonObj isKindOfClass:[NSDictionary class]]) {
return nil;
}
return [NSDictionary dictionaryWithDictionary:(NSDictionary *)jsonObj];
}
#end
call like this:
let data = "x%DAe%91%C1%92%9B0%0C%86%9F%A5%3A%B3%C1%84%98%89%B9%F4%D0%F3%3EA%E9xd%5B%807%06S%23%B2%DD%EE%EC%BB%D7%24%E9%B4%9D%1E%3CcI%BF%A5O%BF%DF%21D%7B%D1%AF%23%21C%0BP%00%C7e%D5%26Et%16W%A6%04%ED%D7w%D8%BC%CB%D5s%D3%08%21T%16%AD6%26%82V%3Cn%BA%8Fi%DA%1B%EC%09%E2%DB%2B%A5%0A%C0e%E9%D1f%21%8C%CCK%DB%95%5D9%FA%80O%D5%E15%A2wq%1E%F6s%B0sW6%95%11%A7%DE%08el%D5%98S%D3H%A4%B3%B4u%AD%B0%E9%E5%09%0F%2F%CB%F0%D9O8%D0s%1C%D2%B1%2B%BFo%18%3C%BFue%25%C4%A7%AE%5C%FDOz%0A%7E%F2%DC%95gq%C9%99%1D%93%7E%40%5B%15%FB%8E%C8%3E%CE%19%E4%CB%E8g%CC%A5%D9%DB%CB%8C%D3%CE%26%A5%CC%89%40W%0A%D0%1E%B3%BC%0F8%40%3Bo%21%14%90b+%CDo%0B%DD%1A%E1%E6%7C%7C%DE%98%DC-%BCzG%BF%C3%BCz%22%0C%EC%27%FA%23%C0%8D%C7%982%E6%A3E%16e%A7%9D%1E%E3%1C%93%DEM%CD%F4b%9F%19%FC%95VF%BE%8B%B6%95%92%FE%D7Z%10%19r%B9%E8%87%F5w%BA5%26%BE3%27%1BW%D6%8F%25%B2%F5%7F%87%C7%EA%E3%5B%01%93%93%FA%FF%CF%05%7B%A6Z%2A%EC%8DR%27ekS%F7R%D6X%2BS%29stX%C1%C7%2F%7B%CD%B12"
if let dict = data.transformZLibData() as? [String:Any] { }
I am trying to encrypt an xml string.After the encryption is done then the decrypt the encrypted d I am getting the string as ALIGNMENT.
I dont understand what is the reason
(NSString*) doCipher:(NSString*)plainText:(CCOperation)encryptOrDecrypt {
const void *vplainText;
size_t plainTextBufferSize;
if (encryptOrDecrypt == kCCDecrypt)
{
NSData *EncryptData = [NSData dataFromBase64String:plainText];
plainTextBufferSize = [EncryptData length];
vplainText = [EncryptData bytes];
}
else
{
plainTextBufferSize = [plainText length];
vplainText = (const void *) [plainText UTF8String];
}
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
// uint8_t iv[kCCBlockSize3DES];
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// memset((void *) iv, 0x0, (size_t) sizeof(iv));
NSString *key = #"123456789012345678901234";
NSString *initVec = #"init Vec";
const void *vkey = (const void *) [key UTF8String];
const void *vinitVec = (const void *) [initVec UTF8String];
ccStatus = CCCrypt(encryptOrDecrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding,
vkey, //"123456789012345678901234", //key
kCCKeySize3DES,
vinitVec, //"init Vec", //iv,
vplainText, //"Your Name", //plainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
//if (ccStatus == kCCSuccess) NSLog(#"SUCCESS");
//else/
if (ccStatus == kCCParamError) return #"PARAM ERROR";
else if (ccStatus == kCCBufferTooSmall) return #"BUFFER TOO SMALL";
else if (ccStatus == kCCMemoryFailure) return #"MEMORY FAILURE";
else if (ccStatus == kCCAlignmentError) return #"ALIGNMENT";
else if (ccStatus == kCCDecodeError) return #"DECODE ERROR";
else if (ccStatus == kCCUnimplemented) return #"UNIMPLEMENTED";
NSString *result;
if (encryptOrDecrypt == kCCDecrypt)
{
result = [ [NSString alloc] initWithData: [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSASCIIStringEncoding];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
result = [myData base64EncodedString];
}
return result;
}
kCCAlignmentError means that the data you are passing is not correctly padded (specifically that the entire data length including padding is not a multiple of the block size). The most likely cause is that you are truncating your encrypted data somewhere, possibly outside of this routine.
You should check your encrypted data at each step and make sure that it is always a multiple of the block size (8 bytes). You'll need to base64-decode before checking the length.
i am trying to encrypt my data using before sending it to server, is there any highly secure two way encryption algorithm ? which one is best for this purpose.
Check ths once
Here, key is string variable, declare as a global variable.
add sequrity framework for your code and import
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
- (void)viewDidLoad
{
[super viewDidLoad];
key=#"Your own key";
// encoding
NSString *encodingString=[[self encrypt:[#"Your String"
dataUsingEncoding:NSUTF8StringEncoding]
base64EncodedString];;
//decoding
NSData *data=[self decrypt:[NSData dataFromBase64String:encryptString]];
NSString *decodingString = [[NSString alloc] initWithBytes:[data bytes] length:
[data length] encoding: NSASCIIStringEncoding];
}
- (NSData *) encrypt:(NSData *) plainText {
return [self transform:kCCEncrypt data:plainText];
}
- (NSData *) decrypt:(NSData *) cipherText {
return [self transform:kCCDecrypt data:cipherText];
}
- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {
// kCCKeySizeAES128 = 16 bytes
// CC_MD5_DIGEST_LENGTH = 16 bytes
NSData* secretKey = [ChipperObject md5:Key];
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
status = CCCryptorCreate(encryptOrDecrypt,
kCCAlgorithmAES128,kCCOptionPKCS7Padding,
[secretKey bytes], kCCKeySizeAES128, iv, &cryptor);
if (status != kCCSuccess) {
return nil;
}
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length],
true);
void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
buf, bufsize, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (status != kCCSuccess) {
free(buf);
CCCryptorRelease(cryptor);
return nil;
}
bytesTotal += bufused;
CCCryptorRelease(cryptor);
return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}
Here is my code using 3des CCCrypt Method,Find GTMBase64.h from googlecode, https://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMBase64.h?r=87
#import <CommonCrypto/CommonCryptor.h>
#import "GTMBase64.h"
- (NSData*)TripleDES:(NSData*)plainData encryptOrDecrypt:(CCOperation)encryptOrDecrypt key:(NSString*)key {
const void *vplainText;
size_t plainTextBufferSize;
if (encryptOrDecrypt == kCCDecrypt)
{
NSData *EncryptData = [GTMBase64 decodeData:plainData];
plainTextBufferSize = [EncryptData length];
vplainText = [EncryptData bytes];
}
else
{
plainTextBufferSize = [plainData length];
vplainText = (const void *)[plainData bytes];
}
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
// uint8_t ivkCCBlockSize3DES;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
// memset((void *) iv, 0x0, (size_t) sizeof(iv));
// NSString *key = #"123456789012345678901234";
NSString *initVec = #"init Vec";
const void *vkey = (const void *) [key UTF8String];
const void *vinitVec = (const void *) [initVec UTF8String];
ccStatus = CCCrypt(encryptOrDecrypt,
kCCAlgorithm3DES,
kCCOptionPKCS7Padding,
vkey, //"123456789012345678901234", //key
kCCKeySize3DES,
vinitVec, //"init Vec", //iv,
vplainText, //"Your Name", //plainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
//if (ccStatus == kCCSuccess) NSLog(#"SUCCESS");
/*else if (ccStatus == kCC ParamError) return #"PARAM ERROR";
else if (ccStatus == kCCBufferTooSmall) return #"BUFFER TOO SMALL";
else if (ccStatus == kCCMemoryFailure) return #"MEMORY FAILURE";
else if (ccStatus == kCCAlignmentError) return #"ALIGNMENT";
else if (ccStatus == kCCDecodeError) return #"DECODE ERROR";
else if (ccStatus == kCCUnimplemented) return #"UNIMPLEMENTED"; */
NSData *result;
if (encryptOrDecrypt == kCCDecrypt)
{
result = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
result = [GTMBase64 encodeData:myData];
}
return result;
}
Usage
NSString *inputString = #"good";
//encode
NSData *inputData = [inputString dataUsingEncoding:NSUTF8StringEncoding];
NSData *encriptdata = [self TripleDES:inputData encryptOrDecrypt:kCCEncrypt key:#"ff68f8e82961489a8b14b345"];
NSString *encodeString = [GTMBase64 stringByEncodingData:encriptdata];
NSLog(#"encodeString : %#" ,encodeString);
//decode
NSData *encodeData = [GTMBase64 decodeString:encodeString];
NSData *decodeData = [self TripleDES:encodeData encryptOrDecrypt:kCCDecrypt key:#"ff68f8e82961489a8b14b345"];
NSString *decodeString = [[NSString alloc] initWithBytes:[decodeData bytes] length:[decodeData length] encoding:NSUTF8StringEncoding];
NSLog(#"decodeString : %#" ,decodeString);
Public Key Infrastructure (PKI) offers you a trustworthy way to encrypt data between 2 machines. You can give it a try.
You can use HTTPS, or you can also use RC6 to encrypt your data.
I'm programming a client on the iPhone. I want to send some strings, and receive an image from the server.
I found this tutorial (http://www.devx.com/wireless/Article/43551), it has been very useful. It works if I want to receive strings, but now I want to receive an image, and I can't make it work.
This is my code when the iPhone receives data. It's a mix made with the tutorial and this answer from JeremyP (http://stackoverflow.com/questions/4613218):
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable: {
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buf[102400];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:102400];
if(len) {
[data appendBytes:(const void *)buf length:len];
// Recibir img
uint8_t size; // Let's make sure size is an explicit width.
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [iStream read: &size maxLength: sizeof size];
while (bytesRead > 0 && totalBytesRead + bytesRead < sizeof size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: &size + totalBytesRead maxLength: (sizeof size) - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail
}
if (totalBytesRead < sizeof size) {
// connection closed before we got the whole size, report and bail
}
size = ntohl(size); // assume wire protocol uses network byte ordering
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: size];
totalBytesRead = 0;
bytesRead = [iStream read: [buffer mutableBytes] maxLength: size];
while (bytesRead > 0 && totalBytesRead + bytesRead < size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: [buffer mutableBytes] + totalBytesRead maxLength: size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
if (totalBytesRead < size) {
// connection closed before we got the whole image, report and bail (not forgetting to release buffer)
}
else {
[buffer setLength: size];
}
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
[data release];
data = nil;
}
else {
NSLog(#"No data.");
}
} break;
}}
It doesn't work... could you help me?
Well, I made it work this way, but I'm no sure if there's a better way.
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
}
} break;
}}
With this method, the received image must be smaller than max_size.
If you know a better way to do this, please let me know! ;)
If all you want to do is download an image from the server to display, take a look at this:
https://github.com/michaelkamprath/iPhoneMK/tree/master/Views/MKNetworkImageView
There are a lot of built in functions to the iOS that will handle image downloading for you. That is, if you can encapsulate the entities you want to download as separate URLs (e.g., a web server).
If, however, you are trying to send and receive data across the same TCP connection, I would strongly advise that you change to a more RESTful approach. Partly because it is easier to implement from the client side, partly because you don't have to worry (as much) about the underlying TCP connection.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I create a zip file by using Objective C?
I request a zip file from my server, using NSData to preserve the data.Then I want to save these data into a zip file, how can I do that with objective-c.
I use the following two methods.
Compress:
+(NSData*) compressData:(NSData*) uncompressedData {
if ([uncompressedData length] == 0) return uncompressedData;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[uncompressedData bytes];
strm.avail_in = (unsigned int)[uncompressedData length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = (unsigned int)([compressed length] - strm.total_out);
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
Uncompress:
+(NSData*) uncompressGZip(NSData*) compressedData {
if ([compressedData length] == 0) return compressedData;
NSUInteger full_length = [compressedData length];
NSUInteger half_length = [compressedData length] / 2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[compressedData bytes];
strm.avail_in = (unsigned int)[compressedData 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 = (unsigned int)([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;
}
}