OpenAL making glitch when looping sound - iphone

I'm playing sounds for my game with openAL and I have some problems that sometimes a small glitch is played while looping. Also without looping I get a small pop...sometimes but not all.
I think it has something to do with the buffer being a little too long so there is some undefined data in the end. I just can't figure out how to change this. I'm loading a caf file with this function:
void* MyGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei *outSampleRate, ALdouble *duration) {
OSStatus err = noErr;
SInt64 theFileLengthInFrames = 0;
AudioStreamBasicDescription theFileFormat;
UInt32 thePropertySize = sizeof(theFileFormat);
ExtAudioFileRef extRef = NULL;
void* theData = NULL;
AudioStreamBasicDescription theOutputFormat;
// Open a file with ExtAudioFileOpen()
err = ExtAudioFileOpenURL(inFileURL, &extRef);
if(err) { printf("MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", err); goto Exit; }
// Get the audio data format
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", err); goto Exit; }
if (theFileFormat.mChannelsPerFrame > 2) { printf("MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); goto Exit;}
// Set the client format to 16 bit signed integer (native-endian) data
// Maintain the channel count and sample rate of the original source format
theOutputFormat.mSampleRate = theFileFormat.mSampleRate;
theOutputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame;
theOutputFormat.mFormatID = kAudioFormatLinearPCM;
theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame;
theOutputFormat.mFramesPerPacket = 1;
theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame;
theOutputFormat.mBitsPerChannel = 16;
theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
// Set the desired client (output) data format
err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
if(err) { printf("MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", err); goto Exit; }
// Get the total frame count
thePropertySize = sizeof(theFileLengthInFrames);
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", err); goto Exit; }
// Read all the data into memory
UInt32 dataSize = theFileLengthInFrames * theOutputFormat.mBytesPerFrame;;
theData = malloc(dataSize);
if (theData)
{
AudioBufferList theDataBuffer;
theDataBuffer.mNumberBuffers = 1;
theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame;
theDataBuffer.mBuffers[0].mData = theData;
// Read the data into an AudioBufferList
err = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer);
if(err == noErr)
{
// success
*outDataSize = (ALsizei)dataSize;
*outDataFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
*outSampleRate = (ALsizei)theOutputFormat.mSampleRate;
}
else
{
// failure
free (theData);
theData = NULL; // make sure to return NULL
printf("MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err); goto Exit;
}
}
// Alex(Colombiamug): get the file duration...
// first, get the audioID for the file...
AudioFileID audioID;
UInt32 audioIDSize = sizeof(audioID);
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_AudioFile, &audioIDSize, &audioID);
if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_AudioFile) FAILED, Error = %ld\n", err); goto Exit; }
//now the duration...
double soundDuration;
UInt32 durationSize = sizeof(soundDuration);
err = AudioFileGetProperty(audioID, kAudioFilePropertyEstimatedDuration, &durationSize, &soundDuration);
if(err) { printf("MyGetOpenALAudioData: AudioFileGetProperty(kAudioFilePropertyEstimatedDuration) FAILED, Error = %ld\n", err); goto Exit; }
*duration = soundDuration;
//printf("Audio duration:%f secs.\n", soundDuration);
Exit:
// Dispose the ExtAudioFileRef, it is no longer needed
if (extRef) ExtAudioFileDispose(extRef);
return theData;
}
It is part of this soundengine: SoundEngine
I have tried to put my caf file directly into the sample code and it is the same small glitch. (This caf file was doing fine with the old Apple SoundEngine.cpp but I had other issues with that so i decided to change)

Answering my own question ;)
By pure luck I must admit I tried to remove the kAudioFormatFlagIsPacked flag from this line:
theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
and that fixed it.
If anybody can tell me why it could be nice to know..or if there are some problems in removing that flag I would also like to hear about it.

Related

read subject key identifier extension with mbedTLS

The project I have to extend is using mbedTLS and I have to extract the subject key identifier extension from the certificate. I have not found a workable solution so far. mbedTLS does not offer a direct function for this.
I have found mbedtls_x509_get_extbut this seems to be an internal function and very low level. I also do not have the offsets. I have also found the v3_ext storing maybe all extension as an mbedtls_x509_buf. I guess this could be parsed as ASN.1. a) Is the v3_extparsing approach the only option and correct? b) Are there better options?
Since no one had an idea how to do it, I followed the approach to parse the v3_ext field of the mbedtls_x509_crt struct.
#include "mbedtls/x509_crt.h"
#include <mbedtls/oid.h>
#include "mbedtls/platform.h"
const uint8_t SKID[] = {0x55, 0x1D, 0x0E}; //!< Subject key identifer OID.
int load_skid(const char* path, uint8_t* skid[]) {
int err = 0;
mbedtls_x509_crt cert;
mbedtls_x509_buf buf;
mbedtls_asn1_sequence extns;
mbedtls_asn1_sequence *next;
memset(&extns, 0, sizeof(extns));
mbedtls_x509_crt_init(&cert);
size_t tag_len;
if (mbedtls_x509_crt_parse_file(&cert, path)) {
err = 1;
goto exit;
}
buf = cert.v3_ext;
if (mbedtls_asn1_get_sequence_of(&buf.p, buf.p + buf.len, &extns, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
err = 1;
goto exit;
}
next = &extns;
while (next) {
if (mbedtls_asn1_get_tag(&(next->buf.p), next->buf.p + next->buf.len, &tag_len, MBEDTLS_ASN1_OID)) {
err = 1;
goto exit;
}
if (!memcmp(next->buf.p, SKID, tag_len)) {
// get value
// correct length for SEQ TL + SKID OID value = 2 + tag_len
unsigned char *p = next->buf.p + tag_len;
if (mbedtls_asn1_get_tag(&p, p + next->buf.len-2-tag_len, &tag_len, MBEDTLS_ASN1_OCTET_STRING)) {
err = 1;
goto exit;
}
// include OCT TL = 2
if (mbedtls_asn1_get_tag(&p, p + next->buf.len-2, &tag_len, MBEDTLS_ASN1_OCTET_STRING)) {
err = 1;
goto exit;
}
if (tag_len != 20) {
err = 1;
goto exit;
}
memcpy(skid, p, 20);
goto exit;
}
next = next->next;
}
// skid not found
err = 1;
exit:
mbedtls_x509_crt_free(&cert);
mbedtls_asn1_sequence *cur;
next = extns.next;
while (next != NULL) {
cur = next;
next = next->next;
mbedtls_free(cur);
}
return err;
}

Writing buffer of audio samples to aac file using ExtAudioFileWrite for iOS

UPDATE: I have figured this out and posted my solution as an answer to my own question (below)
I am trying to write a simple buffer of audio samples to a file using ExtAudioFileWrite in AAC format.
I have achieved this with the code below to write a mono buffer to a .wav file - however, I cannot do this for stereo or for AAC files which is what I want to do.
Here is what I have so far...
CFStringRef fPath;
fPath = CFStringCreateWithCString(kCFAllocatorDefault,
"/path/to/my/audiofile/audiofile.wav",
kCFStringEncodingMacRoman);
OSStatus err;
int mChannels = 1;
UInt32 totalFramesInFile = 100000;
Float32 *outputBuffer = (Float32 *)malloc(sizeof(Float32) * (totalFramesInFile*mChannels));
////////////// Set up Audio Buffer List ////////////
AudioBufferList outputData;
outputData.mNumberBuffers = 1;
outputData.mBuffers[0].mNumberChannels = mChannels;
outputData.mBuffers[0].mDataByteSize = 4 * totalFramesInFile * mChannels;
outputData.mBuffers[0].mData = outputBuffer;
Float32 audioFile[totalFramesInFile*mChannels];
for (int i = 0;i < totalFramesInFile*mChannels;i++)
{
audioFile[i] = ((Float32)(rand() % 100))/100.0;
audioFile[i] = audioFile[i]*0.2;
}
outputData.mBuffers[0].mData = &audioFile;
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,fPath,kCFURLPOSIXPathStyle,false);
ExtAudioFileRef audiofileRef;
// WAVE FILES
AudioFileTypeID fileType = kAudioFileWAVEType;
AudioStreamBasicDescription clientFormat;
clientFormat.mSampleRate = 44100.0;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mFormatFlags = 12;
clientFormat.mBitsPerChannel = 16;
clientFormat.mChannelsPerFrame = mChannels;
clientFormat.mBytesPerFrame = 2*clientFormat.mChannelsPerFrame;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBytesPerPacket = 2*clientFormat.mChannelsPerFrame;
// open the file for writing
err = ExtAudioFileCreateWithURL((CFURLRef)fileURL, fileType, &clientFormat, NULL, kAudioFileFlags_EraseFile, &audiofileRef);
if (err != noErr)
{
cout << "Problem when creating audio file: " << err << "\n";
}
// tell the ExtAudioFile API what format we'll be sending samples in
err = ExtAudioFileSetProperty(audiofileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);
if (err != noErr)
{
cout << "Problem setting audio format: " << err << "\n";
}
UInt32 rFrames = (UInt32)totalFramesInFile;
// write the data
err = ExtAudioFileWrite(audiofileRef, rFrames, &outputData);
if (err != noErr)
{
cout << "Problem writing audio file: " << err << "\n";
}
// close the file
ExtAudioFileDispose(audiofileRef);
NSLog(#"Done!");
My specific questions are:
How do I set up the AudioStreamBasicDescription for AAC?
Why can't I get stereo to work properly here? If I set the number of channels ('mChannels') to 2 then I get the left channel correctly and distortion in the right channel.
I'd very much appreciate any help - I think I've read almost every page I can find on this and am none the wiser as, while there are similar questions, they usually derive the AudioStreamBasicDescription parameters from some input audio file, which I cannot see the result of. The Apple documentation is no help either.
Many thanks in advance,
Adam
Ok, after some exploration I have figured it out. I have wrapped it as a function that writes random noise to a file. Specifically, it can:
write .wav or .m4a files
write mono or stereo in either format
write the file to a specified path
The function arguments are:
path to audio file to be created
number of channels (max 2)
boolean: compress with m4a (if false, use pcm)
For a stereo M4A file, the function should be called as:
writeNoiseToAudioFile("/path/to/my/audiofile.m4a",2,true);
The source of the function follows. I have tried to comment it as much as possible - I hope it is correct, it certainly works for me, but please say "Adam, you've done this a bit wrong" if there is something I've missed. Good luck! Here is the code:
void writeNoiseToAudioFile(char *fName,int mChannels,bool compress_with_m4a)
{
OSStatus err; // to record errors from ExtAudioFile API functions
// create file path as CStringRef
CFStringRef fPath;
fPath = CFStringCreateWithCString(kCFAllocatorDefault,
fName,
kCFStringEncodingMacRoman);
// specify total number of samples per channel
UInt32 totalFramesInFile = 100000;
/////////////////////////////////////////////////////////////////////////////
////////////// Set up Audio Buffer List For Interleaved Audio ///////////////
/////////////////////////////////////////////////////////////////////////////
AudioBufferList outputData;
outputData.mNumberBuffers = 1;
outputData.mBuffers[0].mNumberChannels = mChannels;
outputData.mBuffers[0].mDataByteSize = sizeof(AudioUnitSampleType)*totalFramesInFile*mChannels;
/////////////////////////////////////////////////////////////////////////////
//////// Synthesise Noise and Put It In The AudioBufferList /////////////////
/////////////////////////////////////////////////////////////////////////////
// create an array to hold our audio
AudioUnitSampleType audioFile[totalFramesInFile*mChannels];
// fill the array with random numbers (white noise)
for (int i = 0;i < totalFramesInFile*mChannels;i++)
{
audioFile[i] = ((AudioUnitSampleType)(rand() % 100))/100.0;
audioFile[i] = audioFile[i]*0.2;
// (yes, I know this noise has a DC offset, bad)
}
// set the AudioBuffer to point to the array containing the noise
outputData.mBuffers[0].mData = &audioFile;
/////////////////////////////////////////////////////////////////////////////
////////////////// Specify The Output Audio File Format /////////////////////
/////////////////////////////////////////////////////////////////////////////
// the client format will describe the output audio file
AudioStreamBasicDescription clientFormat;
// the file type identifier tells the ExtAudioFile API what kind of file we want created
AudioFileTypeID fileType;
// if compress_with_m4a is tru then set up for m4a file format
if (compress_with_m4a)
{
// the file type identifier tells the ExtAudioFile API what kind of file we want created
// this creates a m4a file type
fileType = kAudioFileM4AType;
// Here we specify the M4A format
clientFormat.mSampleRate = 44100.0;
clientFormat.mFormatID = kAudioFormatMPEG4AAC;
clientFormat.mFormatFlags = kMPEG4Object_AAC_Main;
clientFormat.mChannelsPerFrame = mChannels;
clientFormat.mBytesPerPacket = 0;
clientFormat.mBytesPerFrame = 0;
clientFormat.mFramesPerPacket = 1024;
clientFormat.mBitsPerChannel = 0;
clientFormat.mReserved = 0;
}
else // else encode as PCM
{
// this creates a wav file type
fileType = kAudioFileWAVEType;
// This function audiomatically generates the audio format according to certain arguments
FillOutASBDForLPCM(clientFormat,44100.0,mChannels,32,32,true,false,false);
}
/////////////////////////////////////////////////////////////////////////////
///////////////// Specify The Format of Our Audio Samples ///////////////////
/////////////////////////////////////////////////////////////////////////////
// the local format describes the format the samples we will give to the ExtAudioFile API
AudioStreamBasicDescription localFormat;
FillOutASBDForLPCM (localFormat,44100.0,mChannels,32,32,true,false,false);
/////////////////////////////////////////////////////////////////////////////
///////////////// Create the Audio File and Open It /////////////////////////
/////////////////////////////////////////////////////////////////////////////
// create the audio file reference
ExtAudioFileRef audiofileRef;
// create a fileURL from our path
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,fPath,kCFURLPOSIXPathStyle,false);
// open the file for writing
err = ExtAudioFileCreateWithURL((CFURLRef)fileURL, fileType, &clientFormat, NULL, kAudioFileFlags_EraseFile, &audiofileRef);
if (err != noErr)
{
cout << "Problem when creating audio file: " << err << "\n";
}
/////////////////////////////////////////////////////////////////////////////
///// Tell the ExtAudioFile API what format we'll be sending samples in /////
/////////////////////////////////////////////////////////////////////////////
// Tell the ExtAudioFile API what format we'll be sending samples in
err = ExtAudioFileSetProperty(audiofileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(localFormat), &localFormat);
if (err != noErr)
{
cout << "Problem setting audio format: " << err << "\n";
}
/////////////////////////////////////////////////////////////////////////////
///////// Write the Contents of the AudioBufferList to the AudioFile ////////
/////////////////////////////////////////////////////////////////////////////
UInt32 rFrames = (UInt32)totalFramesInFile;
// write the data
err = ExtAudioFileWrite(audiofileRef, rFrames, &outputData);
if (err != noErr)
{
cout << "Problem writing audio file: " << err << "\n";
}
/////////////////////////////////////////////////////////////////////////////
////////////// Close the Audio File and Get Rid Of The Reference ////////////
/////////////////////////////////////////////////////////////////////////////
// close the file
ExtAudioFileDispose(audiofileRef);
NSLog(#"Done!");
}
Don't forget to import the AudioToolbox Framework and to include the header file:
#import <AudioToolbox/AudioToolbox.h>

AudioQueue Output Callback only fires 3 times (nBuffers times)

When I start an audio output process with AudioQueueStart(out.queue, nil), the output callback only fires 3 times (which is the number of allocated buffers).
Here is my Output callback code:
static void AQOutputCallback(void* aqr,
AudioQueueRef outQ,
AudioQueueBufferRef outQB)
{
AQCallbackStruct *aqc = (AQCallbackStruct *) aqr;
NSLog(#"Out");
// Check if AudioQueue is stopped
if (!aqc->run) {
NSLog(#"Stopped");
return;
}
// Processing data
// Check enqueue error
int err = AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);
if (err != noErr) NSLog(#"OutputCallback AudioQueueEnqueueBuffer() %d ", err);
NSLog(#"Enqueued");
}
I think it's due to the lack of buffers, but my output is:
Out
Enqueued
Out
Enqueued
Out
Enqueued
So the first buffer is enqueued before the AudioQueue starts to fill the third one, it should not run out of buffers.
What happens here ?
Edit: Setup code
#define AUDIO_BUFFERS 3
typedef struct AQCallbackStruct {
AudioStreamBasicDescription mDataFormat;
AudioQueueRef queue;
AudioQueueBufferRef mBuffers[AUDIO_BUFFERS];
unsigned long frameSize;
BOOL *run;
} AQCallbackStruct;
// In some method
AQCallbackStruct out;
out.mDataFormat
out.mDataFormat.mFormatID = kAudioFormatLinearPCM;
out.mDataFormat.mSampleRate = 44100.0;
out.mDataFormat.mChannelsPerFrame = 2;
out.mDataFormat.mBitsPerChannel = 16;
out.mDataFormat.mBytesPerPacket =
out.mDataFormat.mBytesPerFrame =
out.mDataFormat.mChannelsPerFrame * sizeof(short int);
out.mDataFormat.mFramesPerPacket = 1;
out.mDataFormat.mFormatFlags =
kLinearPCMFormatFlagIsBigEndian
| kLinearPCMFormatFlagIsSignedInteger
| kLinearPCMFormatFlagIsPacked;
out.frameSize = 735;
int err;
err = AudioQueueNewOutput(&out.mDataFormat,
AQOutputCallback,
&out,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&out.queue);
if (err != noErr) NSLog(#"AudioQueueNewOutput() error: %d", err);
for (int i=0; i<AUDIO_BUFFERS; i++) {
err = AudioQueueAllocateBuffer(out.queue, out.frameSize, &out.mBuffers[i]);
if (err != noErr) NSLog(#"Output AudioQueueAllocateBuffer() error: %d", err);
out.mBuffers[i]->mAudioDataByteSize = out.frameSize;
err = AudioQueueEnqueueBuffer(out.queue, out.mBuffers[i], 0, NULL);
if (err != noErr) NSLog(#"Output AudioQueueEnqueueBuffer() error: %d", err);
}
AudioQueueStart(out.queue, nil);
Please have a look at this page: where to start with audio synthesis on iPhone.
The BleepMachine sample code that's in there is what got me started with this.
I finally found out where the problem was: AudioQueue callback in simulator but not on device
However, the output callback was properly fired in simulator but not on my device, and I still don't know exactly why there are differences in the AudioSession settings.

Unable to Write On CFWriteStreamWrite

i am having trouble in writing data to CFStream.
// i am getting the CFSocketRef and then from it getting native Handle.
CFSocketNativeHandle sock = CFSocketGetNative( [appDelegate getSocketRef]);
Does above Code return me the same handler of the created socket?what ever i write onto stream will be written on the created socket?
// and then wrote
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock,
&readStream, &writeStream);
if (!readStream || !writeStream) {
// close([appDelegate TCPClient]);
// close(sock);
fprintf(stderr, "CFStreamCreatePairWithSocket() failed\n");
return;
}
above works fine,it does not give me failed message
// does not give error ,else portion is executed
if (!CFWriteStreamOpen(writeStream)) {
CFStreamError myErr = CFWriteStreamGetError(writeStream);
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
NSLog(#"kCFStreamErrorDomainPOSIX");
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
// Interpret myErr.error as a MacOS error code.
OSStatus macError = (OSStatus)myErr.error;
// Check other error domains.
NSLog(#"kCFStreamErrorDomainMacOSStatus");
}
}else
/* Send the connect call to stream */
// while (send_len < (originalLength + 1))
{
// if (CFWriteStreamCanAcceptBytes(writeStream))
{
//UInt8 buf[] = "Hello, world";//(unsigned char *) "connectStream"
//CFIndex bufLen = (CFIndex)strlen(buf);
bytes = CFWriteStreamWrite(writeStream,
(unsigned char *) connectStream,
originalLength );
NSLog(#"%#",[[NSString alloc] initWithData:connectStream encoding:NSASCIIStringEncoding] );
if (bytes < 0) {
fprintf(stderr, "CFWriteStreamWrite() failed\n");
// close(sock);
return;
}
send_len += bytes;
}
// close(sock);
CFReadStreamClose(readStream);
CFWriteStreamClose(writeStream);
return;
}
CFWriteStreamCanAcceptBytes always return false so i have commented it and directly wrote bytes,and it blocks the call and does not return any thing neither any byte is written on to the stream,
Can any one please guide me in this rergard?
is there any other way of doing this?
Regards,
Aamir

Unit test in xcode : inconsistent build result

Test Case '-[TestParse testParsing]' started.
/Developer/Tools/RunPlatformUnitTests.include: line 415: 3256 Segmentation fault "${THIN_TEST_RIG}" "${OTHER_TEST_FLAGS}" "${TEST_BUNDLE_PATH}"
/Developer/Tools/RunPlatformUnitTests.include:451: error: Test rig '/Developer/Platforms /iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest'
exited abnormally with code 139 (it may have crashed).
I got this seg fault message while I built test case randomly (sometime it built successfully, sometimes it throws seg fault). I'm not sure how I could fix this error.
Only thing I test here is I wrote one class name Parse with class level method. And in test case I just call it like
var = [Parse methodName:filepath];
method is like this
NSMutableDictionary *tempBox = [[NSMutableDictionary alloc] init];
FILE *fd = fopen([filePath UTF8String], "r");
if(!fd){
NSLog(#"fail to open file\n");
}
char buf[4096], *ptr;
char name[512], description[4096];
int isNewInfo = 2, description_continue = 0;
// for (line = 0; line < [args objectAtIndex:1]; line++) {
// fgets(buf, 4096, fd);
// }
while(fgets(buf, sizeof(buf), fd) != NULL){
if(strcmp(buf, "\n") == 0){
isNewInfo -= 1;
if(isNewInfo == 0){
isNewInfo = 2;
description_continue = 0;
description[strlen(description)-1] = '\0';
[self saveDrinkandResetBuf:name
detail:description box:tempBox];
if(name[0] != 0 || description[0] != 0){
NSLog(#"fail to reset...");
}
}
}
if(description_continue){
strcat(description, buf);
continue;
}
if((ptr = strstr(buf, "Drink Name: "))){
memcpy(name, buf+12, strlen(buf));
name[strlen(name)] = '\0';
continue;
}
if((ptr = strstr(buf, "Description: "))){
memcpy(description, buf+13, strlen(buf));
description_continue = 1;
continue;
}
}
fclose(fd);
NSLog(#"finish parsing section\n");
//[tempBox release];
return tempBox;
Not sure what is going on here..
I suppose, the problem is in array management.
In C if the array is declared in a function (and is not declared as a global or static one), then value of its elements is undefined. So your char description[4096] is filled with any values. And nobody said that '\0' will be there.
And the result of strlen(...) for non-null-terminated char string is not defined. It may result in a memory access violation, as it will keep counting until it reaches the first memory byte whose value is 0.
Moreover, when you call description[strlen(description)-1], strlen can return 0 (imagine that the first value, stored there initially was '\0' and your file was started with two empty lines [to reach this line of code]) - so array index will be -1...