SIGABRT on sprintf - ios

My code keep crashing (it's an old iOS app, without ARC). This is the code in question:
- (NSString *) dataToHex:(NSData *)data {
NSUInteger len2 = [data length] * 2;
unsigned char* chars = (unsigned char*) [data bytes];
char finalChar[len2 + 1];
for(int i = 0; i < len2; i++) {
sprintf(finalChar + (i * 2), "%02x", chars[i]);
}
finalChar[len2] = '\0';
NSString *hexString = [NSString stringWithFormat:#"%s", finalChar];
return hexString;
}
The crash is in the line of sprintf(). Any ideas? I've tried using bigger buffer sizes, but doesn't work.

It looks like this loop:
for(int i = 0; i < len2; i++) {
should be:
for(int i = 0; i < len; i++) {
(otherwise you're reading beyond the end of your input data and writing beyond the end of your output data).

In your case, the size of the finalChar array is len2 + 1. later, in the for loop, by saying
for(int i = 0; i < len2; i++) {
sprintf(finalChar + (i * 2), "%02x", chars[i]);
}
finalChar + (i * 2) will point to out of bound memory at some point (when i will be greater than len2/2) because, i is not limited to data length. Out of bound memory access cause undefined behavior.
I believe, it should be something like
for(int i = 0; i < len2/2 ; i++) {
sprintf(finalChar + (i * 2), "%02x", chars[i]);
}

Related

iOS function leaking memory

I am creating a client socket using POSIX socket. Since this process needs an NSArray to use the data, I wrote the following two loops to convert an unsigned char array to an NSArray and vise versa. I checked the memory situation and noticed that memory usage increases slowly when running through these functions multiple times. Can anyone spot any potential memory leaks?
//read code run in background
NSMutableArray * arr = [[NSMutableArray alloc] init];
NSUInteger i = 0;
NSNumber *aUChar = 0;
for(;;)
{
n = read(sockfd,buffer,SOCKET_SIZE);
if (n > 0)
{
[arr removeAllObjects];
for (i = 0; i < n; i++)
{
aUChar = [NSNumber numberWithUnsignedChar:buffer[i]];
[arr addObject:aUChar];
}
//do sth with arr
}
}
//write code run in main thread when function called
int n=0;
unsigned char buffer[SOCKET_SIZE];
NSUInteger i = 0;
NSNumber *tmpnum;
NSArray *data_arr = [command.arguments objectAtIndex : 0];
for (i = 0; i < SOCKET_SIZE; i++)
{
tmpnum = [data_arr objectAtIndex:i];
buffer[i] = [tmpnum charValue];
}
n = write(sockfd,buffer,TCP_SOCKET_SIZE);

How to transform byte array in short array with Objective-C?

I'm developing a mobile application for iOS related to voice recording.
Due to that fact, I'm developing some different sound effects to modify recorded voice but I have a problem to implement some of them.
I'm trying to create echo/delay effect and I need to transform a byte array into a short array but I have no idea how to do it in Objective-C.
Thanks.
This is my current source code to implement it, but like byte is a very short type, when I apply attenuation (what must return a float value) produce an awful noise in my audio.
- (NSURL *)echo:(NSURL *)input output:(NSURL *)output{
int delay = 50000;
float attenuation = 0.5f;
NSMutableData *audioData = [NSMutableData dataWithContentsOfURL:input];
NSUInteger dataSize = [audioData length] - 44;
NSUInteger audioLength = [audioData length];
NSUInteger newAudioLength = audioLength + delay;
// Copy bytes
Byte *byteData = (Byte*)malloc(audioLength);
memcpy(byteData, [audioData bytes], audioLength);
short *shortData = (short*)malloc(audioLength/2);
// create a new array to store new modify data
Byte *newByteData = (Byte*)malloc(newAudioLength);
newByteData = byteData;
for (int i = 44; i < audioLength - delay; i++)
{
newByteData[i + delay] += byteData[i] * attenuation;
}
// Copy bytes in a new NSMutableData
NSMutableData *newAudioData = [NSMutableData dataWithBytes:newByteData length:newAudioLength];
// Store in a file
[newAudioData writeToFile:[output path] atomically:YES];
// Set WAV size
[[AudioUtils alloc] setAudioFileSize:output];
return output;
}
Finally, I could finish my echo effect implementing these four methods. I hope they will be useful for you.
Byte to short array
- (short *) byte2short:(Byte *)bytes size:(int)size resultSize:(int)resultSize{
short *shorts = (short *)malloc(sizeof(short)*resultSize);
for (int i=0; i < size/2; i++){
shorts[i] = (bytes[i*2+1] << 8) | bytes[i*2];
}
return shorts;
}
Short to byte array
- (Byte *) short2byte:(short *)shorts size:(int)size resultSize:(int)resultSize{
Byte *bytes = (Byte *)malloc(sizeof(Byte)*resultSize);
for (int i = 0; i < size; i++)
{
bytes[i * 2] = (Byte) (shorts[i] & 0x00FF);
bytes[(i * 2) + 1] = (Byte) (shorts[i] >> 8);
shorts[i] = 0;
}
return bytes;
}
Effect
- (NSMutableData *) effect:(NSMutableData *)data delay:(int)delay attenuation:(float)attenuation{
NSUInteger audioLength = [data length];
// Copy original data in a byte array
Byte *byteData = (Byte*)malloc(sizeof(Byte)*audioLength);
memcpy(byteData, [data bytes], audioLength);
short *shortData = (short*)malloc(sizeof(short)*(audioLength/2 + delay));
shortData = [self byte2short:byteData size:(int)audioLength resultSize:(int)audioLength/2 + delay];
// Array to store shorts
short *newShortData = shortData;
for (int i = 44; i < audioLength/2; i++)
{
newShortData[i + delay] += (short)((float)shortData[i] * attenuation);
}
Byte *newByteData = [self short2byte:newShortData size:(int)(audioLength/2 + delay) resultSize:(int)(audioLength + delay*2)];
// Copy bytes to a NSMutableData in order to create new file
NSMutableData *newAudioData = [NSMutableData dataWithBytes:newByteData length:(int)(audioLength + delay*2)];
return newAudioData;
}
Echo effect
- (NSURL *)echo:(NSURL *)input output:(NSURL *)output{
NSMutableData *audioData = [NSMutableData dataWithContentsOfURL:input];
// we call effect method that returns a NSMutableData and create a new file
[[self effect:audioData delay:6000 attenuation:0.5f] writeToFile:[output path] atomically:YES];
// We set file's size (is a method I have implemented)
[[AudioUtils alloc] setAudioFileSize:output];
return output;
}
There's no predefined function that will create a short array from a byte array, but it should be fairly simple to do it with a for loop
// create a short array
short *shortData = malloc(sizeof(short)*audioLength);
for (i=0; i<bytearray.length, i++)
{
shortData[i] = byteData[i];
}
The code is not rigorously correct (meaning I didn't compile it, just wrote it here on the fly), but it should give you an idea on how to do it.
Also be aware that saving audio data with two bytes instead of one can give very different results when playing back, but I'll assume you know how to handle with audio data for your specific purposes.

Creating Random Alpha numeric on IOS

i'm java programmer that 'must' move on to obj-C for a while,
i got some confuse when generating random alphanumeric code... here my javacode:
PS: i want to generate code like this :Gh12PU67, AC88pP13, Bk81gH89
private String generateCode(){
String code = "";
Random r = new Random();
char[] c = new char[]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for(int i = 0; i<4; i++){
int uplow = r.nextInt(2);
String temp = ""+ c[r.nextInt(c.length)];
if(uplow==1)
code = code + temp.toUpperCase();
else
code = code + temp;
if((i+1)%2==0){
code += r.nextInt(10);
code += r.nextInt(10);
}
}
return code;
}
then i create on OBJ-C
-(void)generateCode{
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:4];
for (NSUInteger i = 0U; i < 4; i++) {
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
NSLog(#"s-->%#",s);
}
but i got "HpNz" for result AC88pP13 insted that hve pattern String,string, numeric,numeric, lowescase string,numeric,numeric...
that case screw my life for 3 days...
Your Objective-C code looks good, but (as #Wain correctly said in a comment above),
the Java function function contains logic to insert 2 digits after 2 letters, which you
have not replicated in the Objective-C method.
I would make that logic slightly less obscure and write it as
- (void)generateCode
{
static NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY";
static NSString *digits = #"0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:8];
for (NSUInteger i = 0; i < 2; i++) {
uint32_t r;
// Append 2 random letters:
r = arc4random_uniform((uint32_t)[letters length]);
[s appendFormat:#"%C", [letters characterAtIndex:r]];
r = arc4random_uniform((uint32_t)[letters length]);
[s appendFormat:#"%C", [letters characterAtIndex:r]];
// Append 2 random digits:
r = arc4random_uniform((uint32_t)[digits length]);
[s appendFormat:#"%C", [digits characterAtIndex:r]];
r = arc4random_uniform((uint32_t)[digits length]);
[s appendFormat:#"%C", [digits characterAtIndex:r]];
}
NSLog(#"s-->%#",s);
}
Remark (from the man page):
arc4random_uniform(length) is preferred over arc4random() % length,
as it avoids "modulo bias" when the upper bound is not a power of two.
Remark: A more verbatim translation of the Java code code += r.nextInt(10);
to Objective-C would be
r = arc4random_uniform(10);
[s appendString:[#(r) stringValue]];
which creates a NSNumber object #(r) from the random number, and then
converts that to a string.
if you want a secure random string you should use this code:
#define ASCII_START_NUMERS 0x30
#define ASCII_END_NUMERS 0x39
#define ASCII_START_LETTERS_A 0x41
#define ASCII_END_LETTERS_Z 0x5A
#define ASCII_START_LETTERS_a 0x61
#define ASCII_END_LETTERS_z 0x5A
-(NSString *)getRandomString:(int)length {
NSMutableString *result = [[NSMutableString alloc]init];
while (result.length != length) {
NSMutableData* data = [NSMutableData dataWithLength:1];
SecRandomCopyBytes(kSecRandomDefault, 1, [data mutableBytes]);
Byte currentChar = 0;
[data getBytes:&currentChar length:1];
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (currentChar > ASCII_START_NUMERS && currentChar < ASCII_END_NUMERS) { // 0 to 0
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_A && currentChar < ASCII_END_LETTERS_Z) { // A to Z
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_a && currentChar < ASCII_END_LETTERS_z) { // a to z
[result appendString:s];
continue;
}
}
return result;
}

How to encode a UIImage for JSON transmission?

I'm trying to build up an NSMutableDictionary to be converted to be json'ed. One of my key-values are the bytes for a png representation of a picture. So I have something like
NSMutableDictionary *jsonDict = [[NSMutableDictionary alloc] init];
....
if ([self hasPhoto])
{
result[#"photo"] = UIImagePNGRepresentation(self.photo);
}
This later blows up, because NSJSONSerialization doesn't do things like NSData objects which is what UIImagePNGRepresenation returns. What is a good way to encode the data? Just UTF8'ing would likely be bad. I'm not that familiar with the guts of what are legal string representations in json.
Update:
I ended up finding this link about using Apple's builtin but unadvertised functions. The code was longer, but I was 2 files less:
NSData *data = UIImageJPEGRepresentation(self.photo, 0.5);
NSString *base64 = nil;
NSUInteger sourceLength = data.length;
NSUInteger encodeBufferLength = ((sourceLength + 2) / 3) * 4 + 1;
char *encodeBuffer = malloc(encodeBufferLength);
int encodedRealLength = b64_ntop(data.bytes, sourceLength, encodeBuffer, encodeBufferLength);
if (encodedRealLength >= 0)
{
base64 = [[NSString alloc] initWithBytesNoCopy: encodeBuffer length: encodedRealLength + 1 encoding: NSASCIIStringEncoding freeWhenDone: YES];
}
else
{
free(encodeBuffer);
}
result[#"photo-jpeg"] = base64;
This also runs about 7X faster than the Base64 solution below. Not that speed mattered AT ALL in this particular case, but someone asked.
You need to convert your image to base64 string .So that you can pass transmit using JSON. Here is the link to download base64 class files.
Then initialize this in your view controller.m:
[Base64 initialize];
After that convert your image to NSData and use this code:
NSString *strEncoded = [Base64 encode:webDat];
where webdat is an NSData.
Typically, images are encoded as a base64 string for JSON. There is no built-in way to encode NSData to a base64 string, but the algorithm to do so is fairly well known. Create an NSData category like so:
static char encodingTable[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
#implementation NSData (Base64)
- (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength {
const unsigned char *bytes = [self bytes];
NSMutableString *result = [NSMutableString stringWithCapacity:[self length]];
unsigned long ixtext = 0;
unsigned long lentext = [self length];
long ctremaining = 0;
unsigned char inbuf[3], outbuf[4];
short i = 0;
short charsonline = 0, ctcopy = 0;
unsigned long ix = 0;
while( YES ) {
ctremaining = lentext - ixtext;
if( ctremaining <= 0 ) break;
for( i = 0; i < 3; i++ ) {
ix = ixtext + i;
if( ix < lentext ) inbuf[i] = bytes[ix];
else inbuf [i] = 0;
}
outbuf [0] = (inbuf [0] & 0xFC) >> 2;
outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
outbuf [3] = inbuf [2] & 0x3F;
ctcopy = 4;
switch( ctremaining ) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for( i = 0; i < ctcopy; i++ )
[result appendFormat:#"%c", encodingTable[outbuf[i]]];
for( i = ctcopy; i < 4; i++ )
[result appendFormat:#"%c",'='];
ixtext += 3;
charsonline += 4;
if( lineLength > 0 ) {
if (charsonline >= lineLength) {
charsonline = 0;
[result appendString:#"\n"];
}
}
}
return result;
}
#end
Encoding for JSON then becomes trivial:
NSData *imageData = UIImagePNGRepresentation(self.photo);
NSString *base64String = [imageData base64EncodingWithLineLength:0];
result[#"photo] = base64String;
Note that images taken with iOS devices are quite large. The number of bytes you are transmitting is equal to the width x height x 3. For example an iPhone 5 has an 8MP camera, that is 3264 x 2448 x 3 = 23MB of data. You almost never want to transmit that much data via JSON. So, you'll want to crop the photo or resize it down to something more manageable before sending.

Non repeating random numbers in iOS? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Non repeating random numbers in Objective-C
How to generate non repeating random numbers?
I saw this on many sites but they give in main.c file code.
When I use the main.c file the code working is fine, but when I try to convert in to my.m file it is not working.
example:
I need to get all the numbers between 0-10 randomly.and the numbers should not repeat again.
srand(time(NULL));
int s[10];
BOOL fl = 1;
for (int i = 0; i<10; i++) {
while (fl) {
s[i] = rand()%10;
fl = 0;
for (int j = 0; j < i; j++) {
if (s[j] == s[i]) {fl = 1; j = i+1;}
}
}
}
int n = 10;
NSMutableArray *numbers = [NSMutableArray array];
for (int i = 0; i <= n; i++) {
[numbers addObject:[NSNumber numberWithInt:i]];
}
NSMutableArray *result = [NSMutableArray array];
while ([numbers count] > 0) {
int r = arc4random() % [numbers count];
NSNumber *randomElement = [numbers objectAtIndex:r];
[result addObject:randomElement];
[numbers removeObjectAtIndex:r];
}
NSLog(#"%#", result);
Hope the below lines of code will help you
srand(time(NULL));
int randomIndex = rand() % limit;
[reportIDTextField setText:[NSString stringWithFormat:#"%i", randomIndex]];
Benefit of this code is it won't allow repetitive random numbers. Here limit for random numbers.
Hope this is what you are looking for.
Enjoy Coding :)
NSMutableArray *storeArray = [[NSMutableArray alloc] init];
BOOL record = NO;
int x;
for (int i=0; [storeArray count] < 10; i++) //Loop for generate different random values
{
x = arc4random() % 10;//generating random number
if(i==0)//for first time
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
else
{
for (int j=0; j<= [storeArray count]-1; j++)
{
if (x ==[[storeArray objectAtIndex:j] intValue])
record = YES;
}
if (record == YES)
{
record = NO;
}
else
{
[storeArray addObject:[NSNumber numberWithInt:x]];
}
}
}
NSLog(#" Non Repeated Random Numbers : %#",storeArray);
can u try this code may be it's use full to you
Try this:-
This will produce numbers between 0 to 10 randomly.
srand(time(NULL));
int n = 11;
int card[n];
for (int y=0; y<n; y++) {
card[y] = y;
}
for(int q= 0 ;q<3;q++) {
for (int y=0; y<(n-1); y++) {
int r = y + (arc4random() % (n-y));
int temp = card[y]; card[y] = card[r]; card[r] = temp;
}
}
for (int g=0;g<n ; g++) {
int w = card[g];
NSLog(#"%i",w);
}
You can do something like this
number = (arc4random()%10)+1; //Generates Number from 1 to 10.
save it to an Array
Then you can put a condition,That will check the number whether it is present or not in the array.
if not then add it to the array ,if it is already present then simply discard it.
A NOTE: "Never, ever add or multiply random numbers in an attempt to get 'better' randomness
:)

Resources