What is wrong with this zlib string decompression? - iphone

i'm trying to create a simple stringdecompression algorithm for my app.
/*
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be large enough to hold the entire
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit, destLen
is the actual size of the uncompressed buffer.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
*/
[Base64 initialize];
NSData * data = [Base64 decode:#"MDAwMDAwNTB42vPMVkhKzVNIBeLsnNTMPB0IpVCWWZyVqpAJkalKTVUoS8xTSMpJLC0HALWrEYi="];
NSString * deBase64 = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
int lengteOP = [[deBase64 substringWithRange:NSMakeRange(0,8)] intValue];
NSUInteger lengteIP = [deBase64 length];
const unsigned char *input = (const unsigned char *) [[deBase64 substringFromIndex:8] cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char * dest;
uncompress(dest, lengteOP, input, lengteIP);
A get a EXC_BADD_ACCESS error when i try this.
The string is build with code in delphi using ZLib, same as the library in the iPhone sdk
its a base64 encode string with the first 8 characters representing the length of the string followed by the zlib-ed string.

I did not run the code but your issue is likely to be dest. Here is a snippet from the documentation.
Upon entry, destLen is the total size
of the destination buffer, which must
be large enough to hold the entire
uncompressed data.
The destination needs to have the memory allocated before calling the function, otherwise it will attempt to write data to invalid memory causing EXC_BAD_ACCESS.
Try the following:
unsigned char * dest = malloc(sizeof(unsigned char) * lengteOP);
uncompress(dest, lengteOP, input, lengteIP);
//Use dest (create NSString with proper encoding for example)
free(dest);

- finished code
/*
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be large enough to hold the entire
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit, destLen
is the actual size of the uncompressed buffer.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen));
*/
[Base64 initialize];
NSData * data = [Base64 decode:#"MDAwMDAwNTB42vPMVkhKzVNIBeLsnNTMPB0IpVCWWZyVqpAJkalKTVUoS8xTSMpJLC0HALWrEYi="];
NSString * deBase64 = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
uLongf lengthOriginal = [[deBase64 substringWithRange:NSMakeRange(0,8)] floatValue];
uLongf * lengteOP = malloc(sizeof(uLongf));
lengteOP = &lengthOriginal;
NSUInteger lengteIP = [deBase64 length];
NSString * codedString = [deBase64 substringFromIndex:8];
const unsigned char *input = (const unsigned char *) [codedString cStringUsingEncoding:NSISOLatin1StringEncoding];
unsigned char * dest = malloc((sizeof(unsigned char) * lengthOriginal));
uncompress(dest, lengteOP, input, lengteIP);
NSString * bla = #"Decoded string :";
NSLog([bla stringByAppendingString:[NSString stringWithCString:dest encoding:NSASCIIStringEncoding]]);
free(dest);
free(lengteOP);

Related

NSString into NSMutableData without conversion to NSData

my problem is the following. I would like to encapsulate a NSString in a NSMutableData object. But I would like to do it together with other items and without first encapsulating it into a NSData. It's only bytes after all isn't it?
My final NSMutableData object would look something like
[header | stringLength | NSString]
where header is a char and stringLength is an unsigned short.
I build my packet like this
unsigned short stringLength = myString.length;
NSMutableData* nData = [NSMutableData dataWithBytes:(const void*)&header length:sizeof(char)];
[nData appendBytes:(const void*)&dataLength length:sizeof(unsigned short)];
[nData appendBytes:(const void*)myString length:stringLength];
I would then send this over a gkSession and at the other end I would extract the sting lenght and then the string itself:
NSString* temp = [NSString alloc];
[data getBytes:(void*)&temp range:NSMakeRange(sizeof(char)+sizeof(unsigned short), stringLenght)];
For some reasons this is giving me bad memory access. I suspect that myString.length is not doing exactly what I would expect. Do you have any hints? Thanks in advance.
This line is incorrect:
[nData appendBytes:(const void*)myString length:stringLength];
This is encoding the first part of the underlying NSString structure (which is larger than stringLength).
What you mean is:
[nData appendBytes:[myString UTF8String]
length:[myString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
length is the number of characters. This can be substantially smaller than the number of bytes for multibyte characters.
Just as a side note: if you can shorten your length to 1 byte (0-255), then that encoding is called a Pascal String, and CFString can handle that encoding natively (see CFStringGetPascalString()). Not something you generally want to do, but interesting. It's particularly nice with CFStringCreateWithPascalStringNoCopy(), since you can avoid the memory copy operation entirely. This is mostly for legacy support, and I wouldn't jump through any hoops to use it, but sometimes it's handy.

Objective-C character encoding - Change char to int, and back

Simple task: I need to convert two characters to two numbers, add them together and change that back to an character.
What I have got: (works perfect in Java - where encoding is handled for you, I guess):
int myChar1 = (int)([myText1 characterAtIndex:i]);
int myChar2 = (int)([myText2 characterAtIndex:keyCurrent]);
int newChar = (myChar1 + myChar2);
//NSLog(#"Int's %d, %d, %d", textChar, keyChar, newChar);
char newC = ((char) newChar);
NSString *tmp1 = [NSString stringWithFormat:#"%c", newC];
NSString *tmp2 = [NSString stringWithFormat:#"%#", newString];
newString = [NSString stringWithFormat:#"%#%#", tmp2, tmp1]; //Adding these char's in a string
The algorithm is perfect, but now I can't figure out how to implement encoding properties. I would like to do everything in UTF-8 but have no idea how to get a char's UTF-8 value, for instance. And if I've got it, how to change that value back to an char.
The NSLog in the code outputs the correct values. But when I try to do the opposite with the algorithm (I.e. - the values) then it goes wrong. It gets the wrong character value for weird/odd characters.
NSString works with unichar characters that are 2 bytes long (16 bits). Char is one byte long so you can only store code point from U+0000 to U+00FF (i.e. Basic Latin and Latin-1 Supplement).
You should do you math on unichar values then use +[NSString stringWithCharacters:length:] to create the string representation.
But there is still an issue with that solution. You code may generate code points between U+D800 and U+DFFF that aren't valid Unicode characters. The standard reserves them to encode code points from U+10000 to U+10FFFF in UTF-16 by pairs of 16-bit code units. In such a case, your string would be ill-formed and could neither be displayed nor converted in UTF8.
Also, the temporary variable tmp2 is useless and you should not create a new newString as you concatenate the string but rather use a NSMutableString.
I am assuming that your strings are NSStrings consisting of numerals which represent a number. If that is the case, you could try the following:
Include the following headers:
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
Then use the following code:
// convert NSString to UTF8 string
const char * utf8String1 = [myText1 UTF8String];
const char * utf8String2 = [myText2 UTF8String];
// convert UTF8 string into long integers
long num1 = strtol(utf8String1, NULL 0);
long num2 = strtol(utf8String2, NULL 0);
// perform calculations
long calc = num1 - num2;
// convert calculated value back into NSString
NSString * calcText = [[NSString alloc] initWithFormat:#"%li" calc];
// convert calculated value back into UTF8 string
char calcUTF8[64];
snprintf(calcUTF8, 64, "%li", calc);
// log results
NSLog(#"calcText: %#", calcText);
NSLog(#"calcUTF8: %s", calcUTF8);
Not sure if this is what you meant, but from what I understood, you wanted to create a NSString with the UTF-8 string encoding from a char?
If that's what you want, maybe you can use the initWithCString:encoding: method in NSString.

iPhone . stringWithCString encoding

I am compiling a code segment using something like this:
char* filename = (char*) malloc( fileInfo.size_filename +1 );
unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
filename[fileInfo.size_filename] = '\0';
NSString * strPath = [NSString stringWithCString:filename];
but stringWithCString is deprecated. I am supposed to change that to
NSString * strPath = [NSString stringWithCString:filename encoding:????];
this filename as the name says represents entries on the file system, files and directories. How do I know the encoding filename is using? I mean, I can put UTF-8, but who knows which encoding users around the world will be using. If I choose any encoding I will be limiting that.
How do I solve that to put the correct encoding for each user.
thanks
Actually, for C paths, you want something a bit uglier:
NSString *strPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:filename length:strlen(filename)];
And to go the other way:
const char *cPath = [nsFilename fileSystemRepresentation];

Reversing endianness with memcpy

I'm writing a method that creates an in-memory WAV file. The first 4 bytes of the file should contain the characters 'RIFF', so I'm writing the bytes like this:
Byte *bytes = (Byte *)malloc(len); // overall length of file
char *RIFF = (char *)'RIFF';
memcpy(&bytes[0], &RIFF, 4);
The problem is that this writes the first 4 bytes as 'FFIR', thanks to little-endianness. To correct this problem, I'm just doing this:
Byte *bytes = (Byte *)malloc(len);
char *RIFF = (char *)'FFIR';
memcpy(&bytes[0], &RIFF, 4);
This works, but is there a better-looking way of getting memcpy to reverse the order of the bytes it's writing?
You're doing some bad things with pointers (and some weird but not wrong things). Try this:
Byte *bytes = malloc(len); // overall length of file
char *RIFF = "RIFF";
memcpy(bytes, RIFF, 4);
It'll work fine.

How to Pass byte array as parameter in url in iPhone?

I am using following code to get bytes array. thx to this post.
Data *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);
it is the right method to do so?
Now, How i can pass bytes array into url?
Thank You for Help,
You're using the right method to extract the raw bytes from the data. To get those into a URL, you'll need to convert them to a string. Exactly what string depends on the format that you're submitting (ie. it could be just a list of 1s and 0s, or YES and NO, or any other character(s) as required by the server you're talking to.)